1
0

Add content script and popup for channel whitelist management

- Implement content script to identify member-only videos on YouTube
- Create popup interface for managing a channel whitelist
- Add necessary icons and manifest configuration
This commit is contained in:
Chipperfluff 2026-01-19 18:55:43 +01:00
commit 4bbbcd8040
13 changed files with 154 additions and 0 deletions

57
content.js Normal file
View File

@ -0,0 +1,57 @@
console.log("[MemberFilter] content script loaded");
const seen = new WeakSet();
function findMemberVideos(root = document) {
const badges = root.querySelectorAll(
'badge-shape, ytd-badge-supported-renderer'
);
badges.forEach(badge => {
if (!badge.textContent?.includes("Nur für Kanalmitglieder")) return;
const video =
badge.closest("ytd-rich-item-renderer, ytd-video-renderer, ytd-grid-video-renderer");
if (!video) return;
if (seen.has(video)) return;
seen.add(video);
// ---- extract data ----
const titleEl = video.querySelector("#video-title");
const channelEl =
video.querySelector("ytd-channel-name a") ||
video.querySelector(".ytd-channel-name a");
const title = titleEl?.textContent?.trim() ?? "(no title)";
const url = titleEl?.href ?? "(no url)";
const channel = channelEl?.textContent?.trim() ?? "(no channel)";
console.group("[MemberFilter] Member-only video found");
console.log("Title :", title);
console.log("Channel:", channel);
console.log("URL :", url);
console.log("Node :", video);
console.groupEnd();
});
}
// Initial scan
findMemberVideos();
// Observe dynamic changes
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (!(node instanceof HTMLElement)) continue;
findMemberVideos(node);
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});

BIN
icons/anti-bs-icon-1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
icons/anti-bs-icon-128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
icons/anti-bs-icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

BIN
icons/anti-bs-icon-256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
icons/anti-bs-icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

BIN
icons/anti-bs-icon-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
icons/anti-bs-icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icons/anti-bs-icon-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

23
manifest.json Normal file
View File

@ -0,0 +1,23 @@
{
"manifest_version": 3,
"name": "ANTI-BS",
"description": "for to long youtubers thought we are stupid, now we just ignore them. let them know we are not.",
"version": "0.1.0",
"author": "Chipperfluff (Jack)",
"repo": "<placeholder for now>",
"org": "Chipperfluff",
"permissions": ["storage"],
"host_permissions": ["https://www.youtube.com/*"],
"content_scripts": [
{
"matches": ["https://www.youtube.com/*"],
"js": ["content.js"]
}
],
"action": {
"default_popup": "popup.html"
}
}

14
popup.css Normal file
View File

@ -0,0 +1,14 @@
body {
font-family: sans-serif;
min-width: 220px;
}
ul {
padding-left: 0;
}
li {
display: flex;
justify-content: space-between;
margin: 4px 0;
}

18
popup.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Member Filter</title>
<link rel="stylesheet" href="popup.css" />
</head>
<body>
<h3>Channel Whitelist</h3>
<input id="channelInput" placeholder="Channel name" />
<button id="addBtn">Add</button>
<ul id="channelList"></ul>
<script src="popup.js"></script>
</body>
</html>

42
popup.js Normal file
View File

@ -0,0 +1,42 @@
const input = document.getElementById("channelInput");
const addBtn = document.getElementById("addBtn");
const list = document.getElementById("channelList");
function loadChannels() {
chrome.storage.local.get({ whitelist: [] }, ({ whitelist }) => {
list.innerHTML = "";
whitelist.forEach((name, index) => {
const li = document.createElement("li");
li.textContent = name;
const remove = document.createElement("button");
remove.textContent = "x";
remove.onclick = () => removeChannel(index);
li.appendChild(remove);
list.appendChild(li);
});
});
}
function addChannel() {
const name = input.value.trim();
if (!name) return;
chrome.storage.local.get({ whitelist: [] }, ({ whitelist }) => {
whitelist.push(name);
chrome.storage.local.set({ whitelist }, loadChannels);
});
input.value = "";
}
function removeChannel(index) {
chrome.storage.local.get({ whitelist: [] }, ({ whitelist }) => {
whitelist.splice(index, 1);
chrome.storage.local.set({ whitelist }, loadChannels);
});
}
addBtn.onclick = addChannel;
loadChannels();