Sumon_Kayal

Universal Batoto Image Fix 4.2 (Chromium Tuned)

Dec 13th, 2025 (edited)
48,712
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.78 KB | Fixit | 0 0
  1. // ==UserScript==
  2. // @name Universal Batoto Image Fix
  3. // @namespace Umbrella_Corporation
  4. // @version 4.2.1 (Redirected to the main branch)
  5. // @description Fixes Batoto images. Tuned for Chrome/Edge/Brave. Features: Priority Brute-Force, V8-optimized State, and Attribute Monitoring.
  6. // @run-at document-start
  7. // @grant GM_xmlhttpRequest
  8. // @grant GM_registerMenuCommand
  9. // @connect pastebin.com
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=bato.to
  11. // @updateURL https://pastebin.com/raw/c0mBHwtH
  12. // @downloadURL https://pastebin.com/raw/c0mBHwtH
  13. // @match *://ato.to/*
  14. // @match *://dto.to/*
  15. // @match *://fto.to/*
  16. // @match *://hto.to/*
  17. // @match *://jto.to/*
  18. // @match *://lto.to/*
  19. // @match *://mto.to/*
  20. // @match *://nto.to/*
  21. // @match *://vto.to/*
  22. // @match *://wto.to/*
  23. // @match *://xto.to/*
  24. // @match *://yto.to/*
  25. // @match *://vba.to/*
  26. // @match *://wba.to/*
  27. // @match *://xba.to/*
  28. // @match *://yba.to/*
  29. // @match *://zba.to/*
  30. // @match *://bato.ac/*
  31. // @match *://bato.bz/*
  32. // @match *://bato.cc/*
  33. // @match *://bato.cx/*
  34. // @match *://bato.id/*
  35. // @match *://bato.pw/*
  36. // @match *://bato.sh/*
  37. // @match *://bato.si/*
  38. // @match *://bato.to/*
  39. // @match *://bato.vc/*
  40. // @match *://bato.day/*
  41. // @match *://bato.red/*
  42. // @match *://bato.run/*
  43. // @match *://batoto.in/*
  44. // @match *://batoto.tv/*
  45. // @match *://batotoo.com/*
  46. // @match *://batotwo.com/*
  47. // @match *://batpub.com/*
  48. // @match *://batread.com/*
  49. // @match *://battwo.com/*
  50. // @match *://xbato.com/*
  51. // @match *://xbato.net/*
  52. // @match *://xbato.org/*
  53. // @match *://zbato.com/*
  54. // @match *://zbato.net/*
  55. // @match *://zbato.org/*
  56. // @match *://comiko.net/*
  57. // @match *://comiko.org/*
  58. // @match *://mangatoto.com/*
  59. // @match *://mangatoto.net/*
  60. // @match *://mangatoto.org/*
  61. // @match *://batocomic.com/*
  62. // @match *://batocomic.net/*
  63. // @match *://batocomic.org/*
  64. // @match *://readtoto.com/*
  65. // @match *://readtoto.net/*
  66. // @match *://readtoto.org/*
  67. // @match *://kuku.to/*
  68. // @match *://okok.to/*
  69. // @match *://ruru.to/*
  70. // @match *://xdxd.to/*
  71. // ==/UserScript==
  72.  
  73. /*
  74. ===================== Changelog =====================
  75. v4.2.1 - Redirected to the main branch https://pastebin.com/c0mBHwtH for cross browser support
  76. v4.2 (Chromium Tuned) – Priority Brute Force: Reordered mirror search to try
  77. common servers (m, p, w, a) first.
  78. Eager Loading: Forces 'loading="eager"' during recovery
  79. to bypass Chrome's lazy-load during fixes.
  80. V8 Optimization: Direct property access for max speed.
  81.  
  82. v4.1 (Chrome Opt) – Removed Firefox safety wrappers.
  83. ====================================================
  84. */
  85.  
  86. (function () {
  87. 'use strict';
  88.  
  89. if (window.__BTFX_LOADED__) return;
  90. window.__BTFX_LOADED__ = true;
  91.  
  92. const VERSION = '4.2';
  93. const UPDATE_URL = 'https://pastebin.com/raw/c0mBHwtH';
  94.  
  95. // REGEX: Matches "//k01.", "//n03.", etc.
  96. const HOST_RE = /(^|\/\/)([a-z])(\d+)(\.)/i;
  97.  
  98. // PRIORITY LIST (Chromium Optimized)
  99. // Instead of a-z, we check the most likely active mirrors first.
  100. 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'];
  101. const PRIORITY_NUMBERS = ['01', '03', '00', '02', '04', '05'];
  102.  
  103. /* ---------------- Pastebin updater ---------------- */
  104. (function updater() {
  105. let checked = false;
  106. async function checkUpdate(manual) {
  107. if (checked && !manual) return;
  108. checked = true;
  109. try {
  110. const r = await fetch(UPDATE_URL, {cache: 'no-store'});
  111. const txt = await r.text();
  112. const m = txt.match(/@version\s+([0-9.]+)/i);
  113. if (m && parseFloat(m[1]) > parseFloat(VERSION)) {
  114. if (manual || confirm(`Update available: v${VERSION} -> v${m[1]}`)) window.open(UPDATE_URL, '_blank');
  115. } else if (manual) alert(`Up to date (v${VERSION})`);
  116. } catch (e) {}
  117. }
  118. setTimeout(() => checkUpdate(false), 2000);
  119. if (typeof GM_registerMenuCommand === 'function') GM_registerMenuCommand('Check Updates', () => checkUpdate(true));
  120. })();
  121.  
  122. /* ---------------- Unified Core ---------------- */
  123.  
  124. /**
  125. * Fast Rewrite:
  126. * Immediately swaps 'k' mirrors to 'n' mirrors.
  127. */
  128. function quickFixURL(u) {
  129. if (typeof u === 'string' && /(^|\/\/)k(\d+\.)/i.test(u)) {
  130. return u.replace(/(^|\/\/)k(\d+\.)/i, '$1n$2');
  131. }
  132. return null;
  133. }
  134.  
  135. function rewrite(img) {
  136. let touched = false;
  137. const attributes = ['src', 'data-src', 'srcset'];
  138.  
  139. attributes.forEach(attr => {
  140. const value = img.getAttribute(attr);
  141. if (!value) return;
  142.  
  143. if (attr === 'srcset') {
  144. const newValue = value.split(',').map(p => {
  145. const parts = p.trim().split(/\s+/);
  146. const fixed = quickFixURL(parts[0]);
  147. if (fixed) parts[0] = fixed;
  148. return parts.join(' ');
  149. }).join(', ');
  150. if (newValue !== value) { img.setAttribute(attr, newValue); touched = true; }
  151. }
  152. else {
  153. const fixed = quickFixURL(value);
  154. if (fixed && fixed !== value) {
  155. img.setAttribute(attr, fixed);
  156. touched = true;
  157. }
  158. }
  159. });
  160.  
  161. if (touched) {
  162. img.referrerPolicy = 'no-referrer';
  163. // In Chromium, if we change src, we might want to force eager loading
  164. // to ensure the new URL is fetched immediately.
  165. img.loading = 'eager';
  166. }
  167. return touched;
  168. }
  169.  
  170. /* ---------------- Recovery Logic (V8 Optimized) ---------------- */
  171.  
  172. function recover(event) {
  173. const img = event.currentTarget;
  174.  
  175. // DIRECT DOM STATE (V8 Fast Property Access)
  176. if (!img.btfx) {
  177. img.btfx = {
  178. stage: 'init',
  179. lIdx: 0,
  180. nIdx: 0,
  181. orig: img.src
  182. };
  183. }
  184.  
  185. const state = img.btfx;
  186.  
  187. // Safety: Stop if exhausted
  188. if (state.stage === 'failed') return;
  189.  
  190. let nextUrl = null;
  191.  
  192. // --- PHASE 1: Standard Swap (Ensure 'n' was tried) ---
  193. if (state.stage === 'init') {
  194. state.stage = 'bruteforce';
  195. const simpleFix = quickFixURL(state.orig);
  196.  
  197. if (simpleFix && simpleFix !== img.src) {
  198. nextUrl = simpleFix;
  199. }
  200. }
  201.  
  202. // --- PHASE 2: Priority Brute Force ---
  203. if (!nextUrl) {
  204. // Check limits
  205. if (state.lIdx >= PRIORITY_LETTERS.length) {
  206. state.stage = 'failed';
  207. console.warn('[BTFX] All mirrors failed for:', state.orig);
  208. return;
  209. }
  210.  
  211. const letter = PRIORITY_LETTERS[state.lIdx];
  212. const number = PRIORITY_NUMBERS[state.nIdx];
  213.  
  214. // Replace $2 (Letter) and $3 (Number) in the host
  215. if (HOST_RE.test(state.orig)) {
  216. const replacement = `$1${letter}${number}$4`;
  217. nextUrl = state.orig.replace(HOST_RE, replacement);
  218. } else {
  219. state.stage = 'failed';
  220. return;
  221. }
  222.  
  223. // Advance counters
  224. state.nIdx++;
  225. if (state.nIdx >= PRIORITY_NUMBERS.length) {
  226. state.nIdx = 0;
  227. state.lIdx++;
  228. }
  229. }
  230.  
  231. // Apply the new URL
  232. if (nextUrl && nextUrl !== img.src) {
  233. console.log(`[BTFX] Trying mirror: ${nextUrl}`);
  234.  
  235. const newOnLoad = () => { cleanup(); };
  236. const newOnError = (e) => { cleanup(); recover(e); };
  237.  
  238. const cleanup = () => {
  239. img.removeEventListener('load', newOnLoad);
  240. img.removeEventListener('error', newOnError);
  241. };
  242.  
  243. img.addEventListener('load', newOnLoad);
  244. img.addEventListener('error', newOnError);
  245.  
  246. // Force browser to fetch immediately, bypassing lazy load
  247. img.loading = 'eager';
  248. img.referrerPolicy = 'no-referrer';
  249. img.src = nextUrl;
  250. }
  251. }
  252.  
  253. /* ---------------- Pipeline ---------------- */
  254.  
  255. function processImage(img) {
  256. // 1. Try initial Rewrite
  257. rewrite(img);
  258.  
  259. // 2. Attach Error Listener
  260. if (!img.dataset.btfxAttached) {
  261. img.dataset.btfxAttached = "1";
  262. img.addEventListener('error', recover);
  263.  
  264. // Check if image is already dead (Chrome/Edge optimization)
  265. if (img.complete && img.naturalWidth === 0) {
  266. recover({ currentTarget: img });
  267. }
  268. }
  269. }
  270.  
  271. function scan(root = document) {
  272. if (root instanceof HTMLImageElement) {
  273. processImage(root);
  274. } else if (root.querySelectorAll) {
  275. root.querySelectorAll('img').forEach(processImage);
  276. }
  277. }
  278.  
  279. // Initialization
  280. scan();
  281. document.addEventListener('DOMContentLoaded', () => scan());
  282. window.addEventListener('load', () => scan());
  283.  
  284. // Attribute Monitor (Chrome MutationObserver is very fast)
  285. const mo = new MutationObserver(mutations => {
  286. for (const mutation of mutations) {
  287. if (mutation.type === 'childList') {
  288. for (const node of mutation.addedNodes) {
  289. if (node.nodeType === 1) scan(node);
  290. }
  291. } else if (mutation.type === 'attributes') {
  292. if (mutation.target.tagName === 'IMG') {
  293. processImage(mutation.target);
  294. }
  295. }
  296. }
  297. });
  298.  
  299. mo.observe(document.documentElement, {
  300. childList: true,
  301. subtree: true,
  302. attributes: true,
  303. attributeFilter: ['src', 'data-src', 'srcset']
  304. });
  305.  
  306. })();
Advertisement
Add Comment
Please, Sign In to add comment