Greasy Fork

8chan Spoiler Disabler

Disables image and video spoilers on 8chan (moe/se/cc) by replacing both custom and default spoiler placeholders with thumbnails, including dynamically loaded posts.

目前为 2025-04-17 提交的版本。查看 最新版本

// ==UserScript==
// @name         8chan Spoiler Disabler
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Disables image and video spoilers on 8chan (moe/se/cc) by replacing both custom and default spoiler placeholders with thumbnails, including dynamically loaded posts.
// @author       impregnator
// @match        https://8chan.moe/*
// @match        https://8chan.se/*
// @match        https://8chan.cc/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Function to process images and replace spoiler placeholders with thumbnails
    function processImages(images) {
        images.forEach(img => {
            // Check if the image is a spoiler placeholder (custom or default)
            if (img.src.includes('custom.spoiler') || img.src.includes('spoiler.png')) {
                // Get the parent <a> element containing the full-sized file URL
                const link = img.closest('a.imgLink');
                if (link) {
                    // Extract the full-sized file URL
                    const fullFileUrl = link.href;
                    // Extract the file hash (everything after /.media/ up to the extension)
                    const fileHash = fullFileUrl.match(/\/\.media\/([a-f0-9]+)\.[a-z0-9]+$/i);
                    if (fileHash && fileHash[1]) {
                        // Construct the thumbnail URL using the current domain
                        const thumbnailUrl = `${window.location.origin}/.media/t_${fileHash[1]}`;
                        // Replace the spoiler image with the thumbnail
                        img.src = thumbnailUrl;
                    }
                }
            }
        });
    }

    // Process existing images on page load
    const initialImages = document.querySelectorAll('.uploadCell img');
    processImages(initialImages);

    // Set up MutationObserver to handle dynamically added posts
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length) {
                // Check each added node for new images
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const newImages = node.querySelectorAll('.uploadCell img');
                        processImages(newImages);
                    }
                });
            }
        });
    });

    // Observe changes to the document body, including child nodes and subtrees
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();