Refactor code structure and enhance comments: improve readability and maintainability across content.js, popup.js, and associated styles
This commit is contained in:
parent
db63c489b8
commit
705e7cad7e
24
content.js
24
content.js
@ -1,11 +1,15 @@
|
||||
// Current settings snapshot.
|
||||
let whitelist = [];
|
||||
let whitelistHandles = [];
|
||||
let debugEnabled = false;
|
||||
const memberOnlyIndex = new Map();
|
||||
const DATA_PREFIX = "chipperfluff-nobs";
|
||||
// In-memory index of known member-only videos.
|
||||
const memberOnlyIndex = new Map(); // id -> { channelKey, hidden }
|
||||
// Data-* attribute prefix for DOM tags.
|
||||
const DATA_PREFIX = "chipperfluff-nobs"; // nobs = "no-bs" (member-only videos)
|
||||
|
||||
/* ---------------- CSS injection ---------------- */
|
||||
|
||||
// Inject a single style tag for hiding matched videos.
|
||||
function injectStyleOnce() {
|
||||
if (document.getElementById("member-filter-style")) return;
|
||||
|
||||
@ -23,6 +27,7 @@ injectStyleOnce();
|
||||
|
||||
/* ---------------- load whitelist ---------------- */
|
||||
|
||||
// Debug helpers (no output unless debug is enabled).
|
||||
function debugLog(...args) {
|
||||
if (!debugEnabled) return;
|
||||
console.log("[MemberFilter]", ...args);
|
||||
@ -38,6 +43,7 @@ function debugGroupEnd() {
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
// Normalize strings so matching is consistent.
|
||||
function normalizeKey(value) {
|
||||
return value
|
||||
.toLowerCase()
|
||||
@ -47,6 +53,7 @@ function normalizeKey(value) {
|
||||
.trim();
|
||||
}
|
||||
|
||||
// Support legacy strings and new { name, handle } entries.
|
||||
function normalizeWhitelist(list) {
|
||||
const names = [];
|
||||
const handles = [];
|
||||
@ -63,6 +70,7 @@ function normalizeWhitelist(list) {
|
||||
return { names, handles };
|
||||
}
|
||||
|
||||
// Read settings and re-apply visibility immediately.
|
||||
function loadSettings() {
|
||||
chrome.storage.local.get({ whitelist: [], debug: false }, data => {
|
||||
const { names, handles } = normalizeWhitelist(data.whitelist);
|
||||
@ -81,11 +89,12 @@ function loadSettings() {
|
||||
|
||||
loadSettings();
|
||||
|
||||
// Reload settings if popup changes them
|
||||
// Reload settings if popup changes them.
|
||||
chrome.storage.onChanged.addListener(loadSettings);
|
||||
|
||||
/* ---------------- detection logic ---------------- */
|
||||
|
||||
// Detect member-only videos and tag them for future updates.
|
||||
function process(root = document) {
|
||||
if (isWhitelistedChannelPage()) return;
|
||||
const badges = root.querySelectorAll("badge-shape");
|
||||
@ -142,6 +151,7 @@ function process(root = document) {
|
||||
});
|
||||
}
|
||||
|
||||
// Apply whitelist to already-tagged member-only videos.
|
||||
function updateKnownVisibility() {
|
||||
if (isWhitelistedChannelPage()) {
|
||||
revealAll();
|
||||
@ -164,17 +174,20 @@ function updateKnownVisibility() {
|
||||
}
|
||||
}
|
||||
|
||||
// Allow full visibility on whitelisted channel pages.
|
||||
function isWhitelistedChannelPage() {
|
||||
const handle = getChannelHandleFromUrl(location.href);
|
||||
if (!handle) return false;
|
||||
return whitelistHandles.includes(normalizeKey(handle));
|
||||
}
|
||||
|
||||
// Extract @handle from a channel URL.
|
||||
function getChannelHandleFromUrl(url) {
|
||||
const match = url.match(/youtube\.com\/@([^/]+)/i);
|
||||
return match ? match[1] : "";
|
||||
}
|
||||
|
||||
// Remove hidden flags from any tagged videos.
|
||||
function revealAll() {
|
||||
const videos = document.querySelectorAll(
|
||||
`[data-${DATA_PREFIX}-hidden="true"]`
|
||||
@ -182,6 +195,7 @@ function revealAll() {
|
||||
videos.forEach(video => video.removeAttribute(`data-${DATA_PREFIX}-hidden`));
|
||||
}
|
||||
|
||||
// Choose a stable identifier for indexing.
|
||||
function getVideoId(video, url) {
|
||||
const dataId = video.getAttribute("data-video-id");
|
||||
if (dataId) return dataId;
|
||||
@ -190,6 +204,7 @@ function getVideoId(video, url) {
|
||||
return fallbackId || "";
|
||||
}
|
||||
|
||||
// Read the channel key from DOM or fallback to text.
|
||||
function getChannelKey(video) {
|
||||
const stored = video.getAttribute(`data-${DATA_PREFIX}-channel`);
|
||||
if (stored) return stored;
|
||||
@ -201,11 +216,13 @@ function getChannelKey(video) {
|
||||
return channel ? normalizeKey(channel) : "";
|
||||
}
|
||||
|
||||
// Find a video element by stored id.
|
||||
function findVideoById(id) {
|
||||
const escaped = cssEscape(id);
|
||||
return document.querySelector(`[data-${DATA_PREFIX}-id="${escaped}"]`);
|
||||
}
|
||||
|
||||
// Safe attribute selector escaping.
|
||||
function cssEscape(value) {
|
||||
if (window.CSS && CSS.escape) return CSS.escape(value);
|
||||
return String(value).replace(/["\\]/g, "\\$&");
|
||||
@ -215,6 +232,7 @@ function cssEscape(value) {
|
||||
|
||||
process();
|
||||
|
||||
// Watch for new items so member-only tags are applied as they load.
|
||||
const observer = new MutationObserver(mutations => {
|
||||
for (const m of mutations) {
|
||||
for (const node of m.addedNodes) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/* Base layout */
|
||||
body {
|
||||
font-family: "Trebuchet MS", "Verdana", sans-serif;
|
||||
min-width: 260px;
|
||||
@ -7,6 +8,7 @@ body {
|
||||
color: #2b2014;
|
||||
}
|
||||
|
||||
/* Title */
|
||||
h3 {
|
||||
margin: 0 0 10px;
|
||||
letter-spacing: 0.4px;
|
||||
@ -25,6 +27,7 @@ h3 {
|
||||
margin: 6px 0 8px;
|
||||
}
|
||||
|
||||
/* Form rows */
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
@ -36,6 +39,7 @@ h3 {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* Inputs */
|
||||
input {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
@ -45,6 +49,7 @@ input {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
button {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #b2985b;
|
||||
@ -64,12 +69,14 @@ button:hover {
|
||||
filter: brightness(0.95);
|
||||
}
|
||||
|
||||
/* List */
|
||||
ul {
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* List rows */
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@ -88,6 +95,7 @@ li button {
|
||||
background: #f2a285;
|
||||
}
|
||||
|
||||
/* Debug toggle row */
|
||||
.toggle {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
|
||||
@ -6,12 +6,14 @@
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Title + short description -->
|
||||
<h3>Channel Whitelist</h3>
|
||||
<p class="subtext">
|
||||
Hide member-only videos by default. Whitelisted creators stay visible.
|
||||
Add the channel name and its @handle or link.
|
||||
</p>
|
||||
|
||||
<!-- Inputs -->
|
||||
<div class="row">
|
||||
<input id="channelInput" placeholder="Channel name" />
|
||||
</div>
|
||||
@ -20,6 +22,7 @@
|
||||
<button id="addBtn">Add</button>
|
||||
</div>
|
||||
|
||||
<!-- Settings -->
|
||||
<div class="row settings">
|
||||
<label class="toggle">
|
||||
<input id="debugToggle" type="checkbox" />
|
||||
@ -31,6 +34,7 @@
|
||||
Debug logs will appear in the console only when enabled.
|
||||
</p>
|
||||
|
||||
<!-- Whitelist list -->
|
||||
<ul id="channelList"></ul>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
|
||||
10
popup.js
10
popup.js
@ -1,3 +1,4 @@
|
||||
// UI elements.
|
||||
const input = document.getElementById("channelInput");
|
||||
const linkInput = document.getElementById("channelLinkInput");
|
||||
const addBtn = document.getElementById("addBtn");
|
||||
@ -5,11 +6,13 @@ const list = document.getElementById("channelList");
|
||||
const debugToggle = document.getElementById("debugToggle");
|
||||
const resetBtn = document.getElementById("resetBtn");
|
||||
|
||||
// Default settings payload.
|
||||
const DEFAULTS = {
|
||||
whitelist: [],
|
||||
debug: false
|
||||
};
|
||||
|
||||
// Render whitelist and debug state.
|
||||
function loadChannels() {
|
||||
chrome.storage.local.get(DEFAULTS, ({ whitelist, debug }) => {
|
||||
list.innerHTML = "";
|
||||
@ -32,6 +35,7 @@ function loadChannels() {
|
||||
});
|
||||
}
|
||||
|
||||
// Add a new whitelist entry with name + handle.
|
||||
function addChannel() {
|
||||
const name = input.value.trim();
|
||||
const link = linkInput.value.trim();
|
||||
@ -49,6 +53,7 @@ function addChannel() {
|
||||
linkInput.value = "";
|
||||
}
|
||||
|
||||
// Normalize storage entries to { name, handle } objects.
|
||||
function normalizeWhitelist(whitelist) {
|
||||
return (whitelist || []).map(item => {
|
||||
if (typeof item === "string") {
|
||||
@ -58,6 +63,7 @@ function normalizeWhitelist(whitelist) {
|
||||
});
|
||||
}
|
||||
|
||||
// Remove a whitelist entry by index.
|
||||
function removeChannel(index) {
|
||||
chrome.storage.local.get(DEFAULTS, ({ whitelist }) => {
|
||||
const entries = normalizeWhitelist(whitelist);
|
||||
@ -66,14 +72,17 @@ function removeChannel(index) {
|
||||
});
|
||||
}
|
||||
|
||||
// Persist debug toggle.
|
||||
function setDebug(enabled) {
|
||||
chrome.storage.local.set({ debug: Boolean(enabled) });
|
||||
}
|
||||
|
||||
// Reset all settings to defaults.
|
||||
function resetDefaults() {
|
||||
chrome.storage.local.set(DEFAULTS, loadChannels);
|
||||
}
|
||||
|
||||
// Accept @handle or full channel URL.
|
||||
function normalizeHandle(value) {
|
||||
const atMatch = value.match(/@([^/?#]+)/);
|
||||
if (atMatch) return atMatch[1].trim();
|
||||
@ -83,6 +92,7 @@ function normalizeHandle(value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Wire UI events.
|
||||
addBtn.onclick = addChannel;
|
||||
debugToggle.onchange = e => setDebug(e.target.checked);
|
||||
resetBtn.onclick = resetDefaults;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user