Release 2026 Build 1
// ==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; } `);