Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Universal Batoto Image Fix
- // @namespace Umbrella_Corporation
- // @version 4.2.1 (Redirected to the main branch)
- // @description Fixes Batoto images. Tuned for Chrome/Edge/Brave. Features: Priority Brute-Force, V8-optimized State, and Attribute Monitoring.
- // @run-at document-start
- // @grant GM_xmlhttpRequest
- // @grant GM_registerMenuCommand
- // @connect pastebin.com
- // @icon https://www.google.com/s2/favicons?sz=64&domain=bato.to
- // @updateURL https://pastebin.com/raw/c0mBHwtH
- // @downloadURL https://pastebin.com/raw/c0mBHwtH
- // @match *://ato.to/*
- // @match *://dto.to/*
- // @match *://fto.to/*
- // @match *://hto.to/*
- // @match *://jto.to/*
- // @match *://lto.to/*
- // @match *://mto.to/*
- // @match *://nto.to/*
- // @match *://vto.to/*
- // @match *://wto.to/*
- // @match *://xto.to/*
- // @match *://yto.to/*
- // @match *://vba.to/*
- // @match *://wba.to/*
- // @match *://xba.to/*
- // @match *://yba.to/*
- // @match *://zba.to/*
- // @match *://bato.ac/*
- // @match *://bato.bz/*
- // @match *://bato.cc/*
- // @match *://bato.cx/*
- // @match *://bato.id/*
- // @match *://bato.pw/*
- // @match *://bato.sh/*
- // @match *://bato.si/*
- // @match *://bato.to/*
- // @match *://bato.vc/*
- // @match *://bato.day/*
- // @match *://bato.red/*
- // @match *://bato.run/*
- // @match *://batoto.in/*
- // @match *://batoto.tv/*
- // @match *://batotoo.com/*
- // @match *://batotwo.com/*
- // @match *://batpub.com/*
- // @match *://batread.com/*
- // @match *://battwo.com/*
- // @match *://xbato.com/*
- // @match *://xbato.net/*
- // @match *://xbato.org/*
- // @match *://zbato.com/*
- // @match *://zbato.net/*
- // @match *://zbato.org/*
- // @match *://comiko.net/*
- // @match *://comiko.org/*
- // @match *://mangatoto.com/*
- // @match *://mangatoto.net/*
- // @match *://mangatoto.org/*
- // @match *://batocomic.com/*
- // @match *://batocomic.net/*
- // @match *://batocomic.org/*
- // @match *://readtoto.com/*
- // @match *://readtoto.net/*
- // @match *://readtoto.org/*
- // @match *://kuku.to/*
- // @match *://okok.to/*
- // @match *://ruru.to/*
- // @match *://xdxd.to/*
- // ==/UserScript==
- /*
- ===================== Changelog =====================
- v4.2.1 - Redirected to the main branch https://pastebin.com/c0mBHwtH for cross browser support
- v4.2 (Chromium Tuned) – Priority Brute Force: Reordered mirror search to try
- common servers (m, p, w, a) first.
- Eager Loading: Forces 'loading="eager"' during recovery
- to bypass Chrome's lazy-load during fixes.
- V8 Optimization: Direct property access for max speed.
- v4.1 (Chrome Opt) – Removed Firefox safety wrappers.
- ====================================================
- */
- (function () {
- 'use strict';
- if (window.__BTFX_LOADED__) return;
- window.__BTFX_LOADED__ = true;
- const VERSION = '4.2';
- const UPDATE_URL = 'https://pastebin.com/raw/c0mBHwtH';
- // REGEX: Matches "//k01.", "//n03.", etc.
- const HOST_RE = /(^|\/\/)([a-z])(\d+)(\.)/i;
- // PRIORITY LIST (Chromium Optimized)
- // Instead of a-z, we check the most likely active mirrors first.
- const PRIORITY_LETTERS = ['m', 'p', 'w', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'o', 'q', 'r', 's', 't', 'u', 'v', 'x', 'y', 'z'];
- const PRIORITY_NUMBERS = ['01', '03', '00', '02', '04', '05'];
- /* ---------------- Pastebin updater ---------------- */
- (function updater() {
- let checked = false;
- async function checkUpdate(manual) {
- if (checked && !manual) return;
- checked = true;
- try {
- const r = await fetch(UPDATE_URL, {cache: 'no-store'});
- const txt = await r.text();
- const m = txt.match(/@version\s+([0-9.]+)/i);
- if (m && parseFloat(m[1]) > parseFloat(VERSION)) {
- if (manual || confirm(`Update available: v${VERSION} -> v${m[1]}`)) window.open(UPDATE_URL, '_blank');
- } else if (manual) alert(`Up to date (v${VERSION})`);
- } catch (e) {}
- }
- setTimeout(() => checkUpdate(false), 2000);
- if (typeof GM_registerMenuCommand === 'function') GM_registerMenuCommand('Check Updates', () => checkUpdate(true));
- })();
- /* ---------------- Unified Core ---------------- */
- /**
- * Fast Rewrite:
- * Immediately swaps 'k' mirrors to 'n' mirrors.
- */
- function quickFixURL(u) {
- if (typeof u === 'string' && /(^|\/\/)k(\d+\.)/i.test(u)) {
- return u.replace(/(^|\/\/)k(\d+\.)/i, '$1n$2');
- }
- return null;
- }
- function rewrite(img) {
- let touched = false;
- const attributes = ['src', 'data-src', 'srcset'];
- attributes.forEach(attr => {
- const value = img.getAttribute(attr);
- if (!value) return;
- if (attr === 'srcset') {
- const newValue = value.split(',').map(p => {
- const parts = p.trim().split(/\s+/);
- const fixed = quickFixURL(parts[0]);
- if (fixed) parts[0] = fixed;
- return parts.join(' ');
- }).join(', ');
- if (newValue !== value) { img.setAttribute(attr, newValue); touched = true; }
- }
- else {
- const fixed = quickFixURL(value);
- if (fixed && fixed !== value) {
- img.setAttribute(attr, fixed);
- touched = true;
- }
- }
- });
- if (touched) {
- img.referrerPolicy = 'no-referrer';
- // In Chromium, if we change src, we might want to force eager loading
- // to ensure the new URL is fetched immediately.
- img.loading = 'eager';
- }
- return touched;
- }
- /* ---------------- Recovery Logic (V8 Optimized) ---------------- */
- function recover(event) {
- const img = event.currentTarget;
- // DIRECT DOM STATE (V8 Fast Property Access)
- if (!img.btfx) {
- img.btfx = {
- stage: 'init',
- lIdx: 0,
- nIdx: 0,
- orig: img.src
- };
- }
- const state = img.btfx;
- // Safety: Stop if exhausted
- if (state.stage === 'failed') return;
- let nextUrl = null;
- // --- PHASE 1: Standard Swap (Ensure 'n' was tried) ---
- if (state.stage === 'init') {
- state.stage = 'bruteforce';
- const simpleFix = quickFixURL(state.orig);
- if (simpleFix && simpleFix !== img.src) {
- nextUrl = simpleFix;
- }
- }
- // --- PHASE 2: Priority Brute Force ---
- if (!nextUrl) {
- // Check limits
- if (state.lIdx >= PRIORITY_LETTERS.length) {
- state.stage = 'failed';
- console.warn('[BTFX] All mirrors failed for:', state.orig);
- return;
- }
- const letter = PRIORITY_LETTERS[state.lIdx];
- const number = PRIORITY_NUMBERS[state.nIdx];
- // Replace $2 (Letter) and $3 (Number) in the host
- if (HOST_RE.test(state.orig)) {
- const replacement = `$1${letter}${number}$4`;
- nextUrl = state.orig.replace(HOST_RE, replacement);
- } else {
- state.stage = 'failed';
- return;
- }
- // Advance counters
- state.nIdx++;
- if (state.nIdx >= PRIORITY_NUMBERS.length) {
- state.nIdx = 0;
- state.lIdx++;
- }
- }
- // Apply the new URL
- if (nextUrl && nextUrl !== img.src) {
- console.log(`[BTFX] Trying mirror: ${nextUrl}`);
- const newOnLoad = () => { cleanup(); };
- const newOnError = (e) => { cleanup(); recover(e); };
- const cleanup = () => {
- img.removeEventListener('load', newOnLoad);
- img.removeEventListener('error', newOnError);
- };
- img.addEventListener('load', newOnLoad);
- img.addEventListener('error', newOnError);
- // Force browser to fetch immediately, bypassing lazy load
- img.loading = 'eager';
- img.referrerPolicy = 'no-referrer';
- img.src = nextUrl;
- }
- }
- /* ---------------- Pipeline ---------------- */
- function processImage(img) {
- // 1. Try initial Rewrite
- rewrite(img);
- // 2. Attach Error Listener
- if (!img.dataset.btfxAttached) {
- img.dataset.btfxAttached = "1";
- img.addEventListener('error', recover);
- // Check if image is already dead (Chrome/Edge optimization)
- if (img.complete && img.naturalWidth === 0) {
- recover({ currentTarget: img });
- }
- }
- }
- function scan(root = document) {
- if (root instanceof HTMLImageElement) {
- processImage(root);
- } else if (root.querySelectorAll) {
- root.querySelectorAll('img').forEach(processImage);
- }
- }
- // Initialization
- scan();
- document.addEventListener('DOMContentLoaded', () => scan());
- window.addEventListener('load', () => scan());
- // Attribute Monitor (Chrome MutationObserver is very fast)
- const mo = new MutationObserver(mutations => {
- for (const mutation of mutations) {
- if (mutation.type === 'childList') {
- for (const node of mutation.addedNodes) {
- if (node.nodeType === 1) scan(node);
- }
- } else if (mutation.type === 'attributes') {
- if (mutation.target.tagName === 'IMG') {
- processImage(mutation.target);
- }
- }
- }
- });
- mo.observe(document.documentElement, {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ['src', 'data-src', 'srcset']
- });
- })();
Advertisement
Add Comment
Please, Sign In to add comment