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
57
content.js
Normal 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
|
After Width: | Height: | Size: 10 KiB |
BIN
icons/anti-bs-icon-128.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
icons/anti-bs-icon-16.png
Normal file
|
After Width: | Height: | Size: 409 B |
BIN
icons/anti-bs-icon-256.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
icons/anti-bs-icon-32.png
Normal file
|
After Width: | Height: | Size: 872 B |
BIN
icons/anti-bs-icon-48.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
icons/anti-bs-icon-512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
icons/anti-bs-icon-64.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
23
manifest.json
Normal 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
@ -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
@ -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
@ -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();
|
||||