The 4chan Cleaner

Release 2026 Build 1

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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;
  }
`);