bag anti bot script
当前为
// ==UserScript==
// @name bagscript
// @description bag anti bot script
// @version 0.5.1
// @license MIT
// @namespace 9e7f6239-592e-409b-913f-06e11cc5e545
// @include https://8chan.moe/v/res/*
// @include https://8chan.se/v/res/*
// @include https://8chan.moe/barchive/res/*
// @include https://8chan.se/barchive/res/*
// @grant unsafeWindow
// @run-at document-idle
// ==/UserScript==
// Script settings
const SPOILER_BORDER = "3px solid red";
const RUDE_FORMATS = ["JPEG", "JPG", "PNG"];
const THREAD_NAME_FILTER = "/bag/";
// Debug settings
const DISABLE_YOU_BYPASS = false;
// State
let manualBypass;
let defaultSpoilerSrc;
const settings = {};
let toolbarVisible = false;
// Loader
(new MutationObserver((_, observer) => {
const threadTitle = document.querySelector("div.opHead > span.labelSubject");
if (threadTitle) {
observer.disconnect();
if (!threadTitle.innerText.includes(THREAD_NAME_FILTER)) {
return;
}
loadSettings();
loadToolbar();
const initialPosts = document.querySelectorAll(".postCell");
initialPosts.forEach((post) => {
handleSpoilers(post);
});
processAllPosts();
postObserver.observe(document, {childList: true, subtree: true});
}
})).observe(document, {childList: true, subtree: true});
// New post observer
const postObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType === 1) {
const isPost = node.classList.contains("postCell");
const isHoverPost = node.classList.contains("quoteTooltip");
const isInlineQuote = node.classList.contains("inlineQuote");
if (isPost) {
handleSpoilers(node);
const id = postId(node);
unsafeWindow.posting.idsRelation[id].forEach((innerPost) => {
processAllPostsById(id);
});
node.querySelectorAll(".quoteLink").forEach((quoteLink) => {
const quotedId = quoteLink.innerText.substring(2);
const quotedPost = document.getElementById(quotedId);
processSinglePost(quotedPost);
});
} else if (isHoverPost || isInlineQuote) {
handleSpoilers(node);
processSinglePost(node);
}
}
}
}
});
const processSinglePost = function(post) {
const id = postId(post);
const isNice = isNiceId(id) || isNicePost(post);
if (isNice) {
unblurPost(post);
} else {
blurPost(post);
}
}
const processAllPosts = function() {
for (const id in unsafeWindow.posting.idsRelation) {
processAllPostsById(id);
}
document.querySelectorAll(".inlineQuote").forEach((inlineQuote) => {
processSinglePost(inlineQuote);
});
const hoverPost = document.querySelector(".quoteTooltip");
if (hoverPost) {
processSinglePost(hoverPost);
}
}
const processAllPostsById = function(id) {
const innerPostsById = unsafeWindow.posting.idsRelation[id];
let isNice = isNiceId(id);
for (const innerPost of innerPostsById) {
const post = innerPost.parentElement;
if (!isNice) {
isNice = isNicePost(post);
if (isNice) break;
}
}
innerPostsById.forEach(innerPost => handlePost(innerPost.parentElement, isNice));
}
const isNiceId = function(id) {
if (!settings.enabled) return true;
if (manualBypass[id]) return true;
const innerPostsById = unsafeWindow.posting.idsRelation[id];
const isOp = innerPostsById.some(innerPost => innerPost.parentElement.classList.contains("opCell"));
if (isOp) return true;
const idAboveThreshold = innerPostsById.length >= settings.postThreshold;
if (idAboveThreshold) return true;
return false;
}
const isNicePost = function(post) {
const postIsByYou = DISABLE_YOU_BYPASS ? false : post.querySelector(".youName");
if (postIsByYou) return true;
const aboveBlThreshold = post.querySelectorAll(".postInfo > .panelBacklinks > a")?.length >= settings.backlinkThreshold;
if (aboveBlThreshold) return true;
if (settings.experimental) {
const images = post.querySelectorAll("img");
const noImages = images.length === 0;
if (noImages) return true;
const hasFunImage = Array.from(images).some((image) => {
const spoilerImage = image.getAttribute("data-spoiler") === "true"
if (spoilerImage) return true;
const format = image?.parentElement?.href?.split("/")?.[4]?.split(".")?.[1]?.toUpperCase();
if (format) {
const notRudeImage = !RUDE_FORMATS.includes(format);
if (notRudeImage) return true;
}
return false;
});
if (hasFunImage) return true;
const hasFunText = post.querySelector(".doomText, .moeText, .redText, .pinkText, .diceRoll");
if (hasFunText) return true;
}
return false;
}
const isRudeId = function(id) {
return settings.experimental && unsafeWindow.posting.idsRelation[id].length === 3;
}
const handlePost = function(post, isNice) {
let bypassButton = post.querySelector(".bypassButton");
if (isNice) {
unblurPost(post);
if (bypassButton) {
bypassButton.style.display = "none";
}
} else {
blurPost(post);
if (bypassButton) {
bypassButton.style.display = "inline";
if (isRudeId(postId(post))) {
bypassButton.style.border = "1px solid red";
}
} else {
bypassButton = bypassButtonForId(postId(post));
post.querySelector(".postInfo.title").appendChild(bypassButton);
}
}
}
const handleSpoilers = function(post) {
const spoilers = post.querySelectorAll("img[src*='spoiler'], img[data-spoiler]");
if (!defaultSpoilerSrc) {
defaultSpoilerSrc = spoilers[0]?.src;
}
spoilers.forEach(spoiler => {
spoiler.setAttribute("data-spoiler", true);
if (settings.revealSpoilers) {
const fileName = spoiler.parentElement.href.split("/")[4].split(".")[0];
spoiler.src = `/.media/t_${fileName}`;
spoiler.style.border = SPOILER_BORDER;
} else {
spoiler.src = defaultSpoilerSrc;
spoiler.style.border = "0";
}
});
}
const blurPost = function(post) {
post.style.display = settings.hideFiltered ? "none" : "block";
post.querySelectorAll("img").forEach((img) => {
img.style.filter = `blur(${settings.blurStrength}px)`;
});
}
const unblurPost = function(post) {
post.style.display = "block";
post.querySelectorAll("img").forEach((img) => {
img.style.filter = "";
});
}
const loadToolbar = function() {
// Toolbar container
const toolbar = document.createElement("div");
document.querySelector("body").appendChild(toolbar);
toolbar.style.backgroundColor = "var(--navbar-text-color)";
toolbar.style.bottom = "0px";
toolbar.style.color = "var(--navbar-text-color)";
toolbar.style.display = "flex";
toolbar.style.gap = "1px";
toolbar.style.right = "0px";
toolbar.style.padding = "1px";
toolbar.style.position = "fixed";
// Toolbar contents container
const toolbarContents = document.createElement("div");
toolbar.appendChild(toolbarContents);
toolbarContents.style.display = "none";
toolbarContents.style.flexDirection = "column";
toolbarContents.style.gap = "1px";
toolbarContents.style.padding = "1px 1px 0 1px";
// Enable checkbox
const enableContainer = container();
toolbarContents.appendChild(enableContainer);
const enableLabel = label("Enable Filter");
enableContainer.appendChild(enableLabel);
const enableCheckbox = checkbox(settings.enabled);
enableContainer.appendChild(enableCheckbox);
enableCheckbox.onchange = () => {
settings.enabled = !settings.enabled;
unsafeWindow.localStorage.setItem("bag_enabled", settings.enabled);
if (settings.enabled) {
processAllPosts();
postObserver.observe(document, {childList: true, subtree: true});
} else {
postObserver.disconnect();
processAllPosts();
}
}
// Post threshold input
const thresholdContainer = container();
toolbarContents.appendChild(thresholdContainer);
const thresholdLabel = label("Post Threshold");
thresholdContainer.appendChild(thresholdLabel);
const thresholdInput = input(settings.postThreshold);
thresholdContainer.appendChild(thresholdInput);
thresholdInput.onchange = () => {
settings.postThreshold = thresholdInput.value;
unsafeWindow.localStorage.setItem("bag_postThreshold", settings.postThreshold);
processAllPosts();
}
// Backlink threshold input
const blThresholdContainer = container();
toolbarContents.appendChild(blThresholdContainer);
const blThresholdLabel = label("Backlink Threshold");
blThresholdContainer.appendChild(blThresholdLabel);
const blThresholdInput = input(settings.backlinkThreshold);
blThresholdContainer.appendChild(blThresholdInput);
blThresholdInput.onchange = () => {
settings.backlinkThreshold = blThresholdInput.value;
setSetting("bag_backlinkThreshold", settings.backlinkThreshold);
processAllPosts();
}
// Blur input
const blurContainer = container();
toolbarContents.appendChild(blurContainer);
const blurLabel = label("Blur Strength");
blurContainer.appendChild(blurLabel);
const blurInput = input(settings.blurStrength);
blurContainer.appendChild(blurInput);
blurInput.onchange = () => {
settings.blurStrength = blurInput.value;
unsafeWindow.localStorage.setItem("bag_blurStrength", settings.blurStrength);
processAllPosts();
}
// Experimental checkbox
const experimentalContaner = container();
toolbarContents.appendChild(experimentalContaner);
const experimentalLabel = label("Experimental Heuristics");
experimentalContaner.appendChild(experimentalLabel);
const experimentalCheckbox = checkbox(settings.experimental);
experimentalContaner.appendChild(experimentalCheckbox);
experimentalCheckbox.onchange = () => {
settings.experimental = !settings.experimental;
unsafeWindow.localStorage.setItem("bag_experimental", settings.experimental);
if (!settings.experimental) {
document.querySelectorAll('.innerPost').forEach(innerPost => {
innerPost.style.borderRight = "1px solid var(--horizon-sep-color)";
});
document.querySelectorAll(".bypassButton").forEach(bypassButton => {
bypassButton.style.border = "1px solid var(--horizon-sep-color)";
});
}
processAllPosts();
}
// Hide filtered checkbox
const hideContainer = container();
toolbarContents.appendChild(hideContainer);
const hideLabel = label("Hide Filtered");
hideContainer.appendChild(hideLabel);
const hideCheckbox = checkbox(settings.hideFiltered);
hideContainer.appendChild(hideCheckbox);
hideCheckbox.onchange = () => {
settings.hideFiltered = !settings.hideFiltered;
unsafeWindow.localStorage.setItem("bag_hideFiltered", settings.hideFiltered);
processAllPosts();
}
// Reveal spoilers checkbox
const revealContainer = container();
toolbarContents.appendChild(revealContainer);
const revealLabel = label("Reveal Spoilers");
revealContainer.appendChild(revealLabel);
const revealCheckbox = checkbox(settings.revealSpoilers);
revealContainer.appendChild(revealCheckbox);
revealCheckbox.onchange = () => {
settings.revealSpoilers = !settings.revealSpoilers;
unsafeWindow.localStorage.setItem("bag_revealSpoilers", settings.revealSpoilers);
document.querySelectorAll(".postCell").forEach(post => handleSpoilers(post));
}
// Toolbar toggle button
const toggleButton = button();
toolbar.appendChild(toggleButton);
toggleButton.innerText = "<<"
toggleButton.style.backgroundColor = "var(--background-color)"
toggleButton.onclick = () => {
toolbarVisible = !toolbarVisible;
toolbarContents.style.display = toolbarVisible ? "flex" : "none";
toggleButton.innerText = toolbarVisible ? ">>" : "<<";
}
}
// Post helpers
const postId = function(post) {
return post.querySelector('.labelId').innerText;
}
// LocalStorage Helpers
const loadSettings = function() {
manualBypass = getManualBypass();
settings.backlinkThreshold = getIntSetting("bag_backlinkThreshold", 3);
settings.blurStrength = getIntSetting("bag_blurStrength", 10);
settings.enabled = getBoolSetting("bag_enabled", true);
settings.experimental = getBoolSetting("bag_experimental", true);
settings.hideFiltered = getBoolSetting("bag_hideFiltered", false);
settings.postThreshold = getIntSetting("bag_postThreshold", 4);
settings.revealSpoilers = getBoolSetting("bag_revealSpoilers", false);
}
function setSetting(name, value) {
unsafeWindow.localStorage.setItem(name, value);
}
function getSetting(name) {
return unsafeWindow.localStorage.getItem(name);
}
function getBoolSetting(name, defaultValue) {
const value = getSetting(name, defaultValue);
if (value === null) return defaultValue;
return value == "true";
}
function getIntSetting(name, defaultValue) {
const value = getSetting(name, defaultValue);
if (value === null) return defaultValue;
return parseInt(value);
}
function getManualBypass() {
const threadId = unsafeWindow.location.pathname.match(/\/v\/res\/(\d+)/)[1];
const bypassVar = "bag_bypass_" + threadId;
const bp = getSetting(bypassVar);
return (bp === null) ? {} : JSON.parse(bp);
}
function setManualBypass() {
const threadId = unsafeWindow.location.pathname.match(/\/v\/res\/(\d+)/)[1];
const bypassVar = "bag_bypass_" + threadId;
const bypassData = JSON.stringify(manualBypass);
unsafeWindow.localStorage.setItem(bypassVar, bypassData);
}
// HTML Helpers
function container() {
const container = document.createElement("div");
container.style.alignItems = "center";
container.style.backgroundColor = "var(--background-color)";
container.style.display = "flex";
container.style.gap = "0.25rem";
container.style.justifyContent = "space-between";
container.style.padding = "0.25rem";
return container;
}
function label(text) {
const label = document.createElement("div");
label.innerText = text;
label.style.color = "white";
return label;
}
function checkbox(initialValue) {
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.style.cursor = "pointer";
checkbox.checked = initialValue;
return checkbox;
}
function input(initialValue) {
const input = document.createElement("input");
input.size = 4;
input.value = initialValue;
return input;
}
function button() {
const button = document.createElement("div");
button.style.alignItems = "center";
button.style.color = "var(--link-color)";
button.style.cursor = "pointer";
button.style.display = "flex";
button.style.padding = "0.25rem 0.75rem";
button.style.userSelect = "none";
return button;
}
function bypassButtonForId(id) {
const border = isRudeId(id)
? "1px solid red"
: "1px solid var(--horizon-sep-color)";
const bypassButton = button();
bypassButton.className = "bypassButton";
bypassButton.innerText = "+";
bypassButton.style.display = "inline";
bypassButton.style.marginLeft = "auto";
bypassButton.style.border = border;
bypassButton.onclick = () => {
bypassButton.style.display = "none";
manualBypass[id] = true;
setManualBypass();
unsafeWindow.posting.idsRelation[id].forEach(otherPostInner => {
unblurPost(otherPostInner.parentElement);
});
};
return bypassButton;
}