4chan Media-B-Gone

Filter media on 4chan using duplicate detection

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         4chan Media-B-Gone
// @namespace    https://boards.4chan.org/
// @version      1.2.2
// @license      GPLv3
// @description  Filter media on 4chan using duplicate detection
// @author       ceodoe
// @match        https://boards.4chan.org/*/thread/*
// @match        https://boards.4chan.org/*/res/*
// @match        https://boards.4chan.org/*/catalog
// @match        https://boards.4chan.org/*/
// @icon         data:image/png;base64,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
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// ==/UserScript==

// Load settings
let filteredImageHashes = GM_getValue("filteredImageHashes", []).filter(e => e.trim() !== "");
let settings = GM_getValue("settings", {
    use4chanX: true,
    hideCompletely: true,
    addTo4chanXFilter: true,
    addTo4chanXFilterNoStub: true,
    hammingDistance: 5,
    nukeBtnText: "☢️",
    showHashInstead: false
});

function main() {
    GM_addStyle(`
        .hidden {
            display: none !important;
        }

        span#fcmbg-settings-btn {
            cursor: pointer;
            user-select: none;
        }

        dialog#fcmbg-settings-dialog::backdrop {
            backdrop-filter: blur(5px);
        }

        dialog#fcmbg-settings-dialog h3 {
            margin: 0;
            margin-bottom: 0.5em;
        }

        dialog#fcmbg-settings-dialog {
            box-sizing: border-box;
            color: inherit;
            background-color: inherit;
            font-family: inherit;
            border-radius: 10px;
            border: 1px solid #888;
            min-width: 40em;
            max-width: 50%;
        }

        span#fcmbg-closebtn {
            cursor: pointer;
            float: right;
        }

        textarea#fcmbg-hashes-textbox {
            width: 98%;
            width: -moz-available;
            width: -webkit-fill-available;
            height: 100px;
            margin-bottom: 0.5em;
            color: inherit;
            background-color: inherit;
        }

        input.fcmbg-indented-checkbox {
            margin-left: 2em;
        }

        input.fcmbg-indented-checkbox-2 {
            margin-left: 4em;
        }

        input[type=checkbox]:disabled + label {
            color: #888;
        }

        .fcmbg-positive {
            color: #0f0;
        }

        .fcmbg-negative {
            color: #f00;
        }

        .fcmbg-positive, .fcmbg-negative {
            font-weight: bold;
        }

        div#fcmbg-save-button-wrapper {
            width: 98%;
            width: -moz-available;
            width: -webkit-fill-available;
            margin: auto;
            margin-top: 2em;
            text-align: center;
        }

        .fcmbg-footnote {
            margin-bottom: 0.2em;
        }

        .fcmbg-nuke-button {
            margin-left: 0.2em;
            cursor: pointer;
            user-select: none;
        }
    `);

    window.addEventListener("load", function () {
        let settingsDialog = this.document.createElement("dialog");
        settingsDialog.id = "fcmbg-settings-dialog";
        settingsDialog.innerHTML = `
            <span id="fcmbg-closebtn" title="Close" onclick="this.closest('dialog').close()">❌</span>
            <h3>☢️ 4chan Media-B-Gone</h3>

            Filtered thumbnail hashes (comma-separated) <sup>[1]</sup> :<br />
            <textarea id="fcmbg-hashes-textbox" placeholder="List of comma-separated hashes">${filteredImageHashes.join(",")}</textarea><br />

            <input type="checkbox" id="fcmbg-checkbox-usefourchanx" ${settings.use4chanX ? "checked" : ""}><label for="fcmbg-checkbox-usefourchanx">Integrate with 4chan X (${is4chanXActive() ? "<span class='fcmbg-positive'>Detected</span>" : "<span class='fcmbg-negative'>Not detected</span>"})</label><br />
                <input type="checkbox" id="fcmbg-checkbox-hidecompletely" class="fcmbg-indented-checkbox" ${settings.hideCompletely ? "checked" : ""}><label for="fcmbg-checkbox-hidecompletely">Hide matched media completely instead of leaving a stub <sup>[2]</sup></label><br />
                <input type="checkbox" id="fcmbg-checkbox-add-to-filter" class="fcmbg-indented-checkbox" ${settings.addTo4chanXFilter ? "checked" : ""}><label for="fcmbg-checkbox-add-to-filter">Add matched media to 4chan X's Image MD5 filter</label><br />
                <input type="checkbox" id="fcmbg-checkbox-add-to-filter-nostub" class="fcmbg-indented-checkbox-2" ${settings.addTo4chanXFilterNoStub ? "checked" : ""}><label for="fcmbg-checkbox-add-to-filter-nostub">Add <code>stub:no;</code> to generated 4chan X filters to override stub setting <sup>[3]</sup></label><br /><br />

            <input type="checkbox" id="fcmbg-checkbox-hash-instead-of-btn" ${settings.showHashInstead ? "checked" : ""}><label for="fcmbg-checkbox-hash-instead-of-btn">Show copiable media hash on posts instead of nuke button</label><br />
            Text to show on the hide button: <input type="text" id="fcmbg-checkbox-nuke-button-text" value="${settings.nukeBtnText || "☢️"}" /><br />

            <br />

            Hamming distance <sup>[4]</sup> : <input type="number" value="${settings.hammingDistance}" max="15" min="0" id="fcmbg-hamming-distance-numeric" /><br /></<br /><br />

            <small>
                <div class="fcmbg-footnote">
                    <sup>[1]</sup> Note that these are <i>average hashes</i>, not MD5 hashes, they are incompatible with 4chan X's hashes
                </div>
                <div class="fcmbg-footnote">
                    <sup>[2]</sup> If stubs are turned off in 4chan X's settings, this setting will have no effect.
                </div>
                <div class="fcmbg-footnote">
                    <sup>[3]</sup> This requires a page reload to take effect since 4chan X doesn't reparse posts unless the page is reloaded.
                </div>
                <div class="fcmbg-footnote">
                    <sup>[4]</sup> Valid values are 0-15. A value of 0 means no tolerance for any differences in the image, a value of 15 means a high tolerance for differences. A value of 5 is ideal.
                </div>
            </small>

            <div id="fcmbg-save-button-wrapper">
                <input type="button" value="Save and reload" id="fcmbg-save-button" />
            </div>
        `;

        document.body.insertAdjacentElement("afterbegin", settingsDialog);

        // Disable all 4chan X related options if it's not detected
        if(!is4chanXActive()) {
            document.querySelector("#fcmbg-checkbox-usefourchanx").disabled = true;
            document.querySelector("#fcmbg-checkbox-hidecompletely").disabled = true;
            document.querySelector("#fcmbg-checkbox-add-to-filter").disabled = true;
            document.querySelector("#fcmbg-checkbox-add-to-filter-nostub").disabled = true;
        }

        document.querySelector("#fcmbg-checkbox-usefourchanx").addEventListener("change", function() {
            if(this.checked) {
                document.querySelector("#fcmbg-checkbox-hidecompletely").disabled = false;
                document.querySelector("#fcmbg-checkbox-add-to-filter").disabled = false;
                document.querySelector("#fcmbg-checkbox-add-to-filter-nostub").disabled = false;
            } else {
                document.querySelector("#fcmbg-checkbox-hidecompletely").disabled = true;
                document.querySelector("#fcmbg-checkbox-add-to-filter").disabled = true;
                document.querySelector("#fcmbg-checkbox-add-to-filter-nostub").disabled = true;
            }
        });

        document.querySelector("#fcmbg-save-button").addEventListener("click", function() {
            settings.use4chanX = document.querySelector("#fcmbg-checkbox-usefourchanx").checked;
            settings.showHashInstead = document.querySelector("#fcmbg-checkbox-hash-instead-of-btn").checked;
            settings.hideCompletely = document.querySelector("#fcmbg-checkbox-hidecompletely").checked;
            settings.addTo4chanXFilter = document.querySelector("#fcmbg-checkbox-add-to-filter").checked;
            settings.addTo4chanXFilterNoStub = document.querySelector("#fcmbg-checkbox-add-to-filter-nostub").checked;
            settings.nukeBtnText = document.querySelector("#fcmbg-checkbox-nuke-button-text").value;
            settings.hammingDistance = document.querySelector("#fcmbg-hamming-distance-numeric").value;
            GM_setValue("settings", settings);

            // Do not reload hashes since user may have edited the list directly
            filteredImageHashes = document.querySelector("#fcmbg-hashes-textbox").value.split(",").map(e => e.trim()).filter(e => e !== "");

            GM_setValue("filteredImageHashes", [...new Set(filteredImageHashes.filter(e => e.trim() !== ""))]);

            location.reload();
        });

        settingsDialog.addEventListener("click", function(event) {
            let rect = this.getBoundingClientRect();
            let isInDialog = (
                rect.top <= event.clientY &&
                event.clientY <= rect.top + rect.height &&
                rect.left <= event.clientX &&
                event.clientX <= rect.left + rect.width
            );

            if(!isInDialog) {
                this.close();
            }
        });


        if(is4chanXActive() && settings.use4chanX) {
            let fcMBGSettingsBtn = document.createElement("span");
            fcMBGSettingsBtn.innerText = "☢️";
            fcMBGSettingsBtn.id = "fcmbg-settings-btn";

            let fcXSettingsBtn = document.querySelector("span#shortcut-settings");
            fcMBGSettingsBtn.classList.add("shortcut");
            fcMBGSettingsBtn.classList.add("brackets-wrap");
            fcXSettingsBtn.insertAdjacentElement("afterend", fcMBGSettingsBtn);
        } else {
            // Thread
            let anchorElem = document.querySelector("div.navLinks.desktop");

            // Index
            if(!anchorElem) {
                anchorElem = document.querySelector("div#ctrl-top");
            }

            // Catalog
            if(!anchorElem) {
                anchorElem = document.querySelector("span.navLinks");
            }

            anchorElem.insertAdjacentHTML("beforeend", `
                [ <a id="fcmbg-settings-btn" href="#">☢️ Media-B-Gone</a> ]
            `);
        }

        document.querySelector("#fcmbg-settings-btn").onclick = function() {
            document.querySelector("#fcmbg-settings-dialog").showModal();
        };

        // Skip initial load if we load into 4chan X catalog, and let the MutationObserver deal with the posts
        if(!document.querySelector("div.board.catalog-small, div.board.catalog-large")) {
            let images = document.querySelectorAll("a.fileThumb > img, a.catalog-link > img.catalog-thumb, div.thread img.thumb");
            let md5Hashes4chanX = [];

            // Mark initial batch parsed before starting observer so we don't process twice
            images.forEach(img => {
                (img.closest("div.postContainer") || img.closest("div.thread")).setAttribute("data-fcmbg-parsed", "1");
            });

            let initialLoop = new Promise((resolve, reject) => {
                let promises = Array.from(images).map(img => {
                    return getImageHash(img.src).then(hash => {
                        post = (img.closest("div.postContainer") || img.closest("div.thread"));

                        if(settings.showHashInstead) {
                            let hashElem = this.document.createElement("span");
                            hashElem.innerText = " " + hash + " ";
                            hashElem.title = "Media hash for Media-B-Gone";

                            let anchorElem = (post.querySelector("div.catalog-stats") || post.querySelector("span.postNum.desktop") || post.querySelector("div.meta"));
                            anchorElem.insertAdjacentElement("afterend", hashElem);
                        }

                        img.setAttribute("data-fcmbg-ahash", hash);
                        for(let i = 0; i < filteredImageHashes.length; i++) {
                            if(hammingDistance(hash, filteredImageHashes[i]) <= settings.hammingDistance) {
                                // Adding an all-zero hash will nuke a ton of unintended media, it represents an image whose pixels are close to being all the same
                                if(hash !== "0000000000000000") {
                                    nukePost(hash, post);
                                    if(settings.use4chanX) {
                                        if(is4chanXActive() && settings.addTo4chanXFilter) {
                                            md5Hashes4chanX.push(img.getAttribute("data-md5"));
                                        }
                                    }
                                    break; // no need to try to hide already hidden post
                                }
                            }
                        }
                    });
                });

                Promise.all(promises).then(resolve).catch(reject);
            });

            initialLoop.then(() => {
                if(is4chanXActive() && settings.addTo4chanXFilter) {
                    if(md5Hashes4chanX.length > 0) {
                        update4chanXFilter(md5Hashes4chanX)
                    }
                }
            });

            for(let i = 0; i < images.length; i++) {
                if(images[i].classList.contains("catalog-thumb")) {
                    addNukeButton(images[i].closest("div.catalog-thread"));
                } else if(images[i].closest("div.postContainer")){
                    addNukeButton(images[i].closest("div.postContainer"));
                } else {
                    addNukeButton(images[i].closest("div.thread"));
                }
            }
        }
    });

    new MutationObserver(function(event) { parseNewPosts(); }).observe(document.querySelector("div.thread") || document.querySelector("div.board"), {subtree: true, childList: true});
}

function parseNewPosts() {
    let images = document.querySelectorAll("a.fileThumb > img, a.catalog-link > img.catalog-thumb, div.thread img.thumb");

    for(let i = 0; i < images.length; i++) {
        let post = (images[i].closest("div.catalog-thread") || images[i].closest("div.thread") || images[i].closest("div.postContainer"));
        if(post.getAttribute("data-fcmbg-parsed")) {
            continue;
        } else {
            post.setAttribute("data-fcmbg-parsed", "1");
            addNukeButton(post);
            processImage(images[i]);
        }
    }
}

async function processImage(img) {
    let hash = await getImageHash(img.src);
    img.setAttribute("data-fcmbg-ahash", hash);

    for(let i = 0; i < filteredImageHashes.length; i++) {
        if(hammingDistance(hash, filteredImageHashes[i]) <= settings.hammingDistance) {
            nukePost(hash, img.closest("div.postContainer"));

            if(is4chanXActive() && settings.addTo4chanXFilter) {
                update4chanXFilter(img.getAttribute("data-md5"));
            }

            break;
        }
    }
}

function addNukeButton(post) {
    if(settings.showHashInstead) {
        return;
    }

    // Try to ascend to an ancestor to avoid duping nuke buttons
    let ancestor = post.closest("div.postContainer") || post;
    if(!ancestor.querySelector(".fcmbg-nuke-button")) {
        post = ancestor;
    } else {
        return;
    }

    let nukeBtn = document.createElement("span");

    nukeBtn.innerText = settings.nukeBtnText || "☢️";
    nukeBtn.title = "Nuke media with 4chan Media-B-Gone";
    nukeBtn.classList.add("fcmbg-nuke-button");
    nukeBtn.addEventListener("click", function() {
        let img = post.querySelector("a.fileThumb > img, a.catalog-link > img.catalog-thumb, div.thread img.thumb");
        let aHash = img.getAttribute("data-fcmbg-ahash");
        let md5hash = img.getAttribute("data-md5");

        if(hammingDistance(aHash, "0000000000000000") <= settings.hammingDistance) {
            alert("You are trying to hide a piece of media which is very close to has to all zeroes. This has unintended consequences and will lead to a lot of false positives when it comes to videos that start with a black or white frame.");
        } else {
            nukePost(aHash, post);

            if(is4chanXActive() && settings.addTo4chanXFilter) {
                update4chanXFilter(md5hash);
            }
        }
    });

    let anchorElem = (post.querySelector("div.catalog-stats") || post.querySelector("span.postNum.desktop") || post.querySelector("div.meta"));
    anchorElem.insertAdjacentElement("afterend", nukeBtn);
}

function nukePost(hash, post) {
    // Refresh hashes in case they were updated in another tab
    filteredImageHashes = GM_getValue("filteredImageHashes", []);
    filteredImageHashes.push(hash);
    document.querySelector("#fcmbg-hashes-textbox").value = filteredImageHashes.join(",");
    GM_setValue("filteredImageHashes", [...new Set(filteredImageHashes.filter(e => e.trim() !== ""))]);
    document.querySelector("textarea#fcmbg-hashes-textbox").value = filteredImageHashes.join(",");

    if(is4chanXActive() && settings.use4chanX) {
        if(post && !post.querySelector("div.stub")) {
            let hideBtn = post.querySelector("a.hide-reply-button");
            if(hideBtn) {
                hideBtn.click();
            }
        }

        if(post && ((is4chanXActive() && settings.hideCompletely) || is4chanXActive() == false)) {
            post.classList.add("hidden");
        }
    } else {
        if(post) {
            post.classList.add("hidden");
        }
    }
}

function update4chanXFilter(newHashes) {
    if(newHashes.constructor == Array) {
        newHashes = newHashes.map(function(e) {
            return `/${e}/${settings.addTo4chanXFilterNoStub ? ";stub:no;" : ""}`;
        });
    } else if(typeof newHashes == "string") {
        newHashes = [`/${newHashes}/${settings.addTo4chanXFilterNoStub ? ";stub:no;" : ""}`];
    }


    document.querySelector("a.settings-link").click();
    document.querySelector("div#overlay").classList.add("hidden");
    document.querySelector("a.tab-filter").click();
    document.querySelector("select[name=filter]").value = "MD5";
    document.querySelector("select[name=filter]").dispatchEvent(new Event("change"));

    let waitFor4chanX = window.setInterval(function() {
        let md5field = document.querySelector("textarea.field[name=MD5]");

        if(md5field) {
            window.clearInterval(waitFor4chanX);
            let md5s = md5field.value.split("\n").map(function(e) { return e.trim(); });
            md5s = md5s.concat(newHashes);

            // Remove dupes
            md5s = [...new Set(md5s)];

            md5field.value = md5s.join("\n");
            md5field.dispatchEvent(new Event("change"));

            document.querySelector("div#overlay").classList.remove("hidden");
            document.querySelector("a.close.fa.fa-times").click();
        }
    }, 100);
}

async function getImageHash(url) {
    return new Promise((resolve, reject) => {
        let img = new Image();
        img.crossOrigin = "Anonymous";
        img.onload = () => {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext("2d");
            canvas.width = 8;
            canvas.height = 8;
            ctx.drawImage(img, 0, 0, 8, 8);

            let imageData = ctx.getImageData(0, 0, 8, 8).data;
            let grayValues = [];

            // Convert to grayscale
            for(let i = 0; i < imageData.length; i += 4) {
                let r = imageData[i];
                let g = imageData[i + 1];
                let b = imageData[i + 2];

                // Grayscale average
                let gray = Math.round((r + g + b) / 3);
                grayValues.push(gray);
            }

            // Compute average brightness
            let avg = grayValues.reduce((sum, val) => sum + val, 0) / grayValues.length;

            // Build hash: 1 if pixel > avg, else 0
            let bits = grayValues.map(v => (v > avg ? 1 : 0)).join('');

            // Convert bits to hex string
            let hash = parseInt(bits, 2).toString(16).padStart(16, '0');

            resolve(hash);
        };
        img.onerror = () => reject(new Error("Failed to load image"));
        img.src = url;
    });
}

function hexToBinary(hex) {
    return hex.split("").map(h =>
        parseInt(h, 16).toString(2).padStart(4, "0")
    ).join("");
}

function hammingDistance(hash1, hash2) {
    let bin1 = hexToBinary(hash1);
    let bin2 = hexToBinary(hash2);

    let dist = 0;
    for(let i = 0; i < bin1.length; i++) {
        if(bin1[i] !== bin2[i]) {
            dist++;
        }
    }
    return dist;
}

function is4chanXActive() {
    return document.documentElement.classList.contains("fourchan-x");
}

main();