在YouTube用户界面添加按钮,本地屏蔽用户的评论区发言。
// ==UserScript==
// @name YouTube Blacklist
// @namespace http://tampermonkey.net/
// @version 1.1
// @license LGPL
// @description 在YouTube用户界面添加按钮,本地屏蔽用户的评论区发言。
// @author Ptilopsis
// @match https://www.youtube.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
// 等待页面加载完成
window.addEventListener('load', function() {
setTimeout(init, 1000);
});
function init() {
if (isChannelPage()) {
const uid = extractUidFromUrl();
if (uid && !document.querySelector('.floating-button')) {
const floatingButton = createButton(uid);
document.body.appendChild(floatingButton);
}
}
// 监听评论区的变化
observeComments();
GM_registerMenuCommand('管理黑名单', showBlacklist);
}
function isChannelPage() {
const path = window.location.pathname;
return /^\/@[\w-]+\/?$/.test(path);
}
function extractUidFromUrl() {
const path = window.location.pathname;
const match = path.match(/^\/@([\w-]+)\/?$/);
return match ? match[1] : null;
}
function createButton(uid) {
const floatingButton = document.createElement('button');
floatingButton.innerText = '加入黑名单';
floatingButton.style.position = 'fixed';
floatingButton.style.bottom = '20px';
floatingButton.style.right = '20px';
floatingButton.style.padding = '10px 20px';
floatingButton.style.border = '1px solid';
floatingButton.style.borderRadius = '4px';
floatingButton.style.cursor = 'pointer';
floatingButton.style.zIndex = 1000;
const style = document.createElement('style');
style.textContent = `
@media (prefers-color-scheme: dark) {
.floating-button {
background-color: rgba(34, 34, 34, 0.95);
color: white;
border-color: white;
}
}
@media (prefers-color-scheme: light) {
.floating-button {
background-color: rgba(255, 255, 255, 0.95);
color: black;
border-color: black;
}
}
`;
document.head.appendChild(style);
floatingButton.classList.add('floating-button');
floatingButton.onclick = () => {
addToBlacklist(uid);
};
return floatingButton;
}
function addToBlacklist(uid) {
let blacklist = GM_getValue('blacklist', []);
if (!blacklist.includes(uid)) {
blacklist.push(uid);
GM_setValue('blacklist', blacklist);
alert(`用户 ${uid} 已加入黑名单`);
} else {
alert(`用户 ${uid} 已在黑名单中`);
}
}
function observeComments() {
const target = document.querySelector('ytd-comments');
if (target) {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.tagName === 'YTD-COMMENT-THREAD-RENDERER') {
blockComment(node);
observeReplies(node);
}
});
}
});
});
observer.observe(target, { childList: true, subtree: true });
}
}
function observeReplies(commentThread) {
const replies = commentThread.querySelector('ytd-comment-replies-renderer');
if (replies) {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.classList && node.classList.contains('style-scope') && node.classList.contains('ytd-comment-view-model')) {
blockComment(node);
}
});
}
});
});
observer.observe(replies, { childList: true, subtree: true });
}
}
function blockComment(comment) {
let blacklist = GM_getValue('blacklist', []);
const authorLink = findAuthorLink(comment);
if (authorLink) {
const commentUid = new URL(authorLink.href).pathname.split('/').pop().replace('@', '');
if (blacklist.includes(commentUid)) {
comment.style.display = 'none';
}
}
}
function findAuthorLink(element) {
if (element.tagName === 'A' && element.href.includes('/@')) {
return element;
}
for (let child of element.children) {
const found = findAuthorLink(child);
if (found) {
return found;
}
}
return null;
}
function showBlacklist() {
let blacklist = GM_getValue('blacklist', []);
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.top = '50%';
panel.style.left = '50%';
panel.style.transform = 'translate(-50%, -50%)';
panel.style.border = '1px solid black';
panel.style.padding = '20px';
panel.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
panel.style.zIndex = 10000;
panel.style.maxWidth = '400px';
panel.style.width = '80%';
panel.style.borderRadius = '8px';
const style = document.createElement('style');
style.textContent = `
@media (prefers-color-scheme: dark) {
.blacklist-panel {
background-color: rgba(34, 34, 34, 0.95);
color: white;
}
.blacklist-panel button {
color: white;
background-color: #444;
}
}
@media (prefers-color-scheme: light) {
.blacklist-panel {
background-color: rgba(255, 255, 255, 0.95);
color: black;
}
.blacklist-panel button {
color: black;
background-color: #ddd;
}
}
`;
document.head.appendChild(style);
panel.classList.add('blacklist-panel');
const title = document.createElement('h2');
title.innerText = '黑名单';
title.style.textAlign = 'center';
title.style.marginBottom = '15px';
panel.appendChild(title);
const closeButton = document.createElement('button');
closeButton.innerText = '❌';
closeButton.style.position = 'absolute';
closeButton.style.top = '10px';
closeButton.style.right = '10px';
closeButton.style.background = 'none';
closeButton.style.border = 'none';
closeButton.style.fontSize = '16px';
closeButton.style.cursor = 'pointer';
closeButton.onclick = () => {
document.body.removeChild(panel);
};
panel.appendChild(closeButton);
const list = document.createElement('ul');
list.style.maxHeight = '200px';
list.style.overflowY = 'auto';
blacklist.forEach(uid => {
const item = document.createElement('li');
const link = document.createElement('a');
link.innerText = uid;
link.href = `https://www.youtube.com/@${uid}`;
link.target = '_blank';
link.style.color = 'inherit';
item.appendChild(link);
item.style.marginBottom = '10px';
const removeButton = document.createElement('button');
removeButton.innerText = '移除';
removeButton.style.marginLeft = '10px';
removeButton.style.border = '1px solid';
removeButton.style.borderRadius = '4px';
removeButton.style.cursor = 'pointer';
removeButton.onclick = () => {
removeFromBlacklist(uid);
panel.remove();
showBlacklist();
};
item.appendChild(removeButton);
list.appendChild(item);
});
panel.appendChild(list);
document.body.appendChild(panel);
}
function removeFromBlacklist(uid) {
let blacklist = GM_getValue('blacklist', []);
blacklist = blacklist.filter(item => item !== uid);
GM_setValue('blacklist', blacklist);
alert(`用户 ${uid} 已从黑名单中移除`);
}
})();