4chan Media-B-Gone

Filter media on 4chan using duplicate detection

// ==UserScript==
// @name         4chan Media-B-Gone
// @namespace    https://boards.4chan.org/
// @version      1.2.1
// @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();