Skip to content

Instantly share code, notes, and snippets.

@mohemohe
Last active June 6, 2022 01:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohemohe/072df94b9e1f9c90ebfe5778be60e784 to your computer and use it in GitHub Desktop.
Save mohemohe/072df94b9e1f9c90ebfe5778be60e784 to your computer and use it in GitHub Desktop.
YouTubeのクソいチャンネルをいい感じに隠すUserScript
// ==UserScript==
// @name YoutubeChannelBlock
// @namespace dev.mohemohe.block.channel.youtube
// @version 11
// @description fuck channel
// @author mohemohe
// @match https://www.youtube.com/*
// @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js
// @grant GM.getValue
// @grant GM.setValue
// ==/UserScript==
const channelRegex = /\/(c([^\/]*)|user)\/([^\/]*)\/?/;
const targetElemName = [
"ytd-rich-grid-media",
"ytd-video-owner-renderer",
"ytd-video-renderer",
"ytd-comment-renderer",
];
class YoutubeChannelBlock {
constructor() {
this.toggleLock = false;
this.channelIdName = {};
this.lastChannelIds = [];
}
async exec() {
await this.mark();
await this.attachCss();
}
async toggleBlockChannel(channelId) {
if (this.toggleLock) {
return;
}
this.toggleLock = true;
let channelIds = await GM.getValue("channelIds", []);
if (channelIds.includes(channelId)) {
console.log("[YoutubeChannelBlock]", "remove channel:", channelId);
channelIds = channelIds.filter((cid) => cid !== channelId);
this.removeCss(channelId);
} else {
console.log("[YoutubeChannelBlock]", "add channel:", channelId, this.channelIdName[channelId]);
channelIds.push(channelId);
}
await GM.setValue("channelIds", channelIds);
await this.attachCss();
this.toggleLock = false;
}
async mark() {
let targets = [];
targetElemName.some((selector) => {
const t = document.querySelectorAll(`${selector}:not([data-channel_id])`);
if (t) {
[...t].forEach((e) => {
if (e.dataset.selector !== selector) {
e.dataset.selector = selector;
}
});
targets.push(...[...t]);
return !["/watch", "/results"].includes(location.pathname);
}
return false;
})
if (targets.length === 0) {
return;
}
const channelIds = await GM.getValue("channelIds", []);
for (const target of [...targets]) {
let a = target.querySelector(`a[href*='/channel/']`);
if (!a) {
a = target.querySelector(`a[href*='/c/']`);
}
if (!a) {
a = target.querySelector(`a[href*='/user/']`);
}
if (!a) {
continue;
}
const { href } = a;
const channelId = href.match(channelRegex);
if (!channelId) {
continue;
}
target.channelName = a.textContent;
target.channelId = channelId[3];
this.channelIdName[target.channelId] = target.channelName;
if (target.dataset.channel_id !== target.channelId) {
target.dataset.channel_id = target.channelId;
const currentButton = target.querySelector(".ycb_block");
if (currentButton) {
currentButton.remove();
}
const button = document.createElement("button");
button.innerText = "ブロック切り替え";
// button.style.position = "absolute";
// button.style.bottom = "0px";
button.style.borderRadius = "2px";
button.style.padding = "2px 15px";
if (["/watch", "/results"].includes(location.pathname)) {
button.style.height = "41px";
button.style.marginRight = "4px";
}
button.style.color = "#ffa566";
button.style.border = "1px solid #ffa566";
button.style.background = "transparent";
button.style.cursor = "pointer";
button.style.alignItems = "center";
button.addEventListener("click", () => this.toggleBlockChannel(target.channelId));
const wrapper = document.createElement("div");
wrapper.className = "ycb_block";
// wrapper.style.position = "relative";
wrapper.style.display = "flex";
wrapper.style.justifyContent = "flex-end";
wrapper.style.alignItems = "center";
wrapper.appendChild(button);
target.insertAdjacentElement("beforeend", wrapper);
}
}
}
async attachCss() {
const channelIds = await GM.getValue("channelIds", []);
const currentCsses = [...document.querySelectorAll(".ycb_blockChannelCss")];
channelIds.forEach((channelId) => {
const nextCss = `
[data-channel_id='${channelId}'] * {
display: none !important;
}
[data-channel_id='${channelId}']:before {
content: ${`"blocked: ${this.channelIdName[channelId]} (${channelId})"`.replaceAll("\n", "")};
font-size: 1.2rem;
display: block !important;
color: white;
}
[data-channel_id='${channelId}'] .ycb_block,
[data-channel_id='${channelId}'] .ycb_block * {
display: flex !important;
}
`;
const currentCss = currentCsses.find((t) => t.dataset.channel_id === channelId);
if (currentCss) {
if (currentCss.originalCss !== nextCss) {
currentCss.textContent = nextCss;
currentCss.originalCss = nextCss;
}
} else {
const style = document.createElement("style");
style.classList.add("ycb_blockChannelCss");
style.dataset.channel_id = channelId;
style.textContent = nextCss;
style.originalCss = nextCss;
document.body.insertAdjacentElement("beforeend", style);
}
});
const systemCss = document.querySelector(`#ycb_systemCss`);
if (!systemCss) {
const style = document.createElement("style");
style.id = "ycb_systemCss";
style.textContent = `
#paid-comment-images {
display: none !important;
}
`;
document.body.insertAdjacentElement("beforeend", style);
}
}
async removeCss(channelId) {
const currentCss = document.querySelector(`.ycb_blockChannelCss[data-channel_id='${channelId}']`);
if (currentCss) {
currentCss.remove();
}
}
}
function main() {
const ycb = new YoutubeChannelBlock();
const watch = new MutationObserver(_.debounce((changes) => {
console.debug("[YoutubeChannelBlock]", "changes:", changes);
ycb.exec(changes);
}), 1000);
const pre = new MutationObserver(_.debounce((changes) => {
const ypm = document.querySelector('ytd-page-manager');
if (ypm) {
watch.observe(ypm, {
childList: true,
subtree: true,
});
pre.disconnect();
}
}), 250);
const body = document.querySelector('body');
pre.observe(body, {
childList: true,
subtree: true,
});
}
window.addEventListener("load", () => {
main();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment