The 4chan Cleaner

Release 2026 Build 1

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name        The 4chan Cleaner
// @description Release 2026 Build 1
// @author      BoKu
// @version     2026.1
// @namespace   https://greasyfork.org/scripts/T4C - The 4chan Cleaner
// @icon        https://i.imgur.com/jsBhOii.gif
// @license 	The 4chan Cleaner is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
// @match       *://*.4chan.org/*
// @exclude     *://p.4chan.org/*
// @noframes
// @run-at      document-body
// @resource    bootstrapCss https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css#sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js#sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI
// @grant       GM.setValue
// @grant       GM.getValue
// @grant       GM.openInTab
// @grant       GM_getResourceText
// @grant       GM_addStyle
// @grant       GM_info
// @grant       unsafeWindow
// @grant       GM_download
// @connect     i.4cdn.org
// ==/UserScript==
'use strict';
const bootstrapCss = GM_getResourceText("bootstrapCss"),
      scriptVersion = GM_info.script.version,
      scriptDesc = GM_info.script.description,
      c = unsafeWindow,
      logo = "https://s.4cdn.org/image/fp/logo-transparent.png",
      h = c.document.querySelector("html"),
      s = c.document.querySelectorAll('head script, head style, link[rel*="stylesheet"]'),
      b = c.document.querySelector('body'),
      d = c.document.getElementById('doc'),
      f = c.document.getElementById('ft'),
      bt = c.document.querySelector("body > div.boardBanner > div.boardTitle")?.textContent || "4chan";
h.setAttribute('data-bs-theme','dark');
GM_addStyle(bootstrapCss);
h.style.background = '#212529';
b.style.background = '#212529';
f?.remove();

const b1 = c.document.querySelector("#delform > div.bottomCtrl.desktop > span.deleteform > input[type=submit]:nth-child(5)");
if (b1) {
    b1.classList.add("btn", "btn-danger");
    b1.style.margin = ".25rem .125rem";
}
const b2 = c.document.querySelector("#bottomReportBtn");
if (b2) {
    b2.classList.add("btn", "btn-warning");
    b2.style.margin = ".25rem .125rem";
}
const i1 = c.document.querySelector("#delform > div.bottomCtrl.desktop > span.deleteform > input[type=text]:nth-child(1)");
if (i1) {
    i1.classList.add("form-control");
}
const i2 = c.document.querySelector("#delform > div.bottomCtrl.desktop > span.deleteform > input[type=text]:nth-child(2)");
if (i2) {
    i2.classList.add("form-control");
}
const i3 = c.document.querySelector("#delPassword");
if (i3) {
    i3.classList.add("form-control");
}
const c1 = c.document.querySelector('#delform .bottomCtrl.desktop .deleteform input[type="checkbox"]:nth-child(3)');
if (c1) {
    c1.classList.add("form-check-input");
    Object.assign(c1.style, {
        minHeight: `calc(1em + 1rem + 2px)`,
        padding: `.5rem 1rem`,
        fontSize: `1.25rem`,
        marginTop: 'unset'
    })
}
const s1 = c.document.querySelector("#styleSelector");
if (s1) {
    s1.classList.add("form-select");
}

function whenReady(fn) {
    if (c.document.readyState !== "loading") {
        fn();
    } else {
        c.document.addEventListener("DOMContentLoaded", fn);
    }
}
function downloadAllImages() {
    const imageLinks = c.document.querySelectorAll('a.fileThumb');
    if (imageLinks.length === 0) {
        console.debug('No images found to download!');
        return;
    }
    const confirmationMessage = `Are you sure you want to download all the ${imageLinks.length} images?`;
    if (!c.confirm(confirmationMessage)) {
        return;
    }
    imageLinks.forEach((link, index) => {
    const imageUrl = link.href;
    // Cleans the URL path down to the pure filename string
    const fileName = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);

    // Staggers requests by 150ms intervals to prevent file streaming bottlenecks
    setTimeout(() => {
      GM_download({
        url: imageUrl,
        name: fileName,
        onload: () => {
          console.log(`Successfully saved: ${fileName}`);
        },
        onerror: (error) => {
          console.error(`Download failed for ${fileName}:`, error.error);

          // Fallback Strategy: Triggers if your browser blocks native extension file generation
          if (error.error === 'not_enabled' || error.error === 'permission_denied') {
             const fallbackAnchor = c.document.createElement('a');
             fallbackAnchor.href = imageUrl;
             fallbackAnchor.download = fileName;
             c.document.body.appendChild(fallbackAnchor);
             fallbackAnchor.click();
             fallbackAnchor.remove();
          }
        }
      });
    }, index * 150);
  });
}
whenReady(() => {
    const nlD = c.document.querySelector("body > div.navLinks.desktop");
    if (!nlD) return;

    setTimeout(() => {
        if (nlD.childElementCount === 7) {
            try {
                const modalWrap = c.document.createElement("div");
                modalWrap.innerHTML = `
                <div class="modal fade" id="T4C_viewImages_modal" tabindex="-1" aria-hidden="true">
                  <div class="modal-dialog modal-dialog-centered modal-lg modal-dialog-scrollable" style="width:90vw!important;min-width:90vw!important;max-width:90vw!important;">
                    <div class="modal-content bg-dark text-light">
                      <div class="modal-header">
                        <h5 class="modal-title">View All Images</h5>
                        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
                      </div>
                      <div class="modal-body" id="T4C_viewImages_modal_body"></div>
                      <div class="modal-footer" id="T4C_viewImages_modal_footer"><small>Doesn't support <b>webm</b> yet.</small></div>
                    </div>
                  </div>
                </div>`;
                c.document.body.appendChild(modalWrap.firstElementChild);

                const modalEl = c.document.getElementById("T4C_viewImages_modal"),
                      modalBody = c.document.getElementById("T4C_viewImages_modal_body");
                function buildThumbs() {
                    modalBody.replaceChildren();
                    const wrap = c.document.createElement("div");
                    wrap.className = "d-flex flex-wrap gap-2";
                    c.document.querySelectorAll("a.fileThumb").forEach((thumb) => {
                        const href = thumb.getAttribute("href") || "";
                        if (href.includes("webm")) return;
                        thumb.querySelectorAll(":scope > img").forEach((img) => {
                            img.classList.add("t4c-thumb");
                        });
                        wrap.appendChild(thumb.cloneNode(true));
                    });
                    modalBody.appendChild(wrap);
                }
                function clearThumbs() {
                    modalBody.replaceChildren();
                }
                nlD.appendChild(c.document.createTextNode("["));
                const vai = c.document.createElement("a");
                vai.id = "T4C_viewImages";
                vai.textContent = "View All Images";
                vai.style.cursor = "pointer";
                vai.dataset.bsBackdrop="static";
                vai.addEventListener("click", (event) => {
                    if (!modalEl) return;
                    const modal = bootstrap.Modal.getOrCreateInstance(modalEl, {
                        backdrop: true,
                        keyboard: true
                    });
                    modal.show();
                })
                nlD.appendChild(vai);
                modalEl.addEventListener("shown.bs.modal", buildThumbs);
                modalEl.addEventListener("hidden.bs.modal", clearThumbs);
                nlD.appendChild(c.document.createTextNode("] ["));
                const dai = c.document.createElement("a");
                dai.id = "T4C_downImages";
                dai.textContent = "Download All Images";
                dai.style.cursor = "pointer";
                dai.addEventListener("click", (event) => {
                    event.preventDefault();
                    downloadAllImages();
                })
                nlD.appendChild(dai);
                nlD.appendChild(c.document.createTextNode("]"));
            } catch (ex) {
                console.debug(ex);
            }
        }
    }, 500);
});

GM_addStyle(`
  * {
    scrollbar-color: rgba(255, 70, 87, 1) black;
  }
  html {
    font-size:75%!important;
  }
  #doc, #doc2, #doc3, #doc4 {
    display:flex;
    flex-direction:column;
    width:unset;
  }
  .boxcontent,
  .box-inner,
  .box-outer,
  #announce,
  #entries,
  #disclaimer-dialog,
  div.reply{
    background:#343a40;
    color:#f8f9fa;
  }
  div.reply{
    border: 1px solid #212529;
    border-left: none;
    border-top: none;
  }
  .boxbar,
  #entries th{
    background:#1a1d20;
    color:#dee2e6;
  }
  div#filter-btn,
  div#opts-btn {
    display:none;
  }
  .boxcontent {
    display:flex;
    flex-wrap:nowrap;
    justify-content:space-around;
    align-items:flex-start;
  }
  #boards .column {
    float:unset;
    width:100%;
  }
  span.warning sup {
    vertical-align:unset!important;
    top:unset;
  }
  div[class="box-outer top-box"],
  #announce{
    border:1px solid #212529;
  }

  /* Normal */
  a, a:visited,
  #boards a,
  div#boardNavDesktop a,
  a.replylink, a.replylink:not(:hover), div#absbot a:not(:hover),
  .quoteLink, .quotelink, .deadlink, .button
  {
    color: rgba(255, 70, 87, 1) !important;
  }
  /* Hover */
  a:hover,
  #boards a:hover,
  div#boardNavDesktop a:hover,
  a.replylink:hover, div.post div.postInfo span.postNum a:hover, .posteruid .hand:hover,
  a.quoteLink:hover, a.quotelink:hover, .button:hover
  {
    color: rgba(234, 134, 143, 1) !important;
  }

  .c-thread img {
    border: 1px solid rgba(220, 53, 69, 1) !important;
  }
  ol, ul {
    padding-left: unset;
  }
  #c-threads{
    display: flex;
    flex-wrap: nowrap;
    justify-content: space-evenly;
    flex-direction: row;
  }
  .c-thread{
    width:100%;
  }
  div#bannerCnt,
  hr.aboveMidAd,
  div.middlead,
  .adl,
  body > hr:nth-child(13),
  footer,
  #absbot,
  hr,
  #delform > div.bottomCtrl.desktop > span.stylechanger,
  #blotter{
    display:none!important;
  }
  hr{
    width:100%!important;
  }
  div.post div.postInfo span.subject {
    color: rgba(13, 202, 240, 1);
  }
  div.post div.postInfo span.nameBlock span.name {
    color: rgba(37, 200, 125, 1);
  }
  .nameBlock.capcodeMod span.name, span.capcodeMod a span.name, span.capcodeMod span.postertrip, span.capcodeMod strong.capcode {
    color: rgba(255, 126, 255,1) !important;
  }
  #delform > div.bottomCtrl.desktop{
    display: flex !important;
    width:100%;
    justify-content: flex-end;
    align-items: center;
  }

  #delform > div.bottomCtrl.desktop > span.deleteform
  {
    display: flex !important;
    align-items: center;
    justify-content: flex-end;
    gap: .5rem;
  }
  .form-check-input:focus {
    border-color: rgba(255, 70, 87, 1);
    outline: 0;
    box-shadow: 0 0 0 .25rem rgba(234, 134, 143, .25) !important;
  }
  .form-check-input:checked {
    background-color: rgba(255, 70, 87, 1);
    border-color: rgba(255, 70, 87, 1);
  }
  div.thread{
    border-bottom:2px solid rgba(255,255,255,.25);
    margin:1rem 0;
  }
  body > div.navLinks.desktop > div > span.ts-replies::before{
    content: "Replies: ";
  }body > div.navLinks.desktop > div > span.ts-images::before{
    content: "Images: ";
  }
  body > div.navLinks.desktop > div > span.ts-page::before{
    content: "Pages: ";
  }
  .fileThumb img,
  #T4C_viewImages_modal_body .t4c-thumb {
    max-height: 125px!important;
    width: auto !important;
  }
`);