Guest User

Universal Batoto Image Fix v3 (Mirror)

a guest
Jan 8th, 2026
14,009
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.18 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Universal Batoto Image Fix
  3. // @namespace Umbrella_Corporation
  4. // @version 3.6
  5. // @description Fixes Batoto-style images using a unified Firefox-safe core with conditional v1.9.1 hybrid recovery (k→n rewrite, retry/backoff, host rotation). Includes optional Pastebin updater.
  6. // @run-at document-start
  7. // @icon https://www.google.com/s2/favicons?sz=64&domain=bato.to
  8. // @match *://ato.to/*
  9. // @match *://bato.to/*
  10. // @match *://bato.si/*
  11. // @match *://bato.ing/*
  12. // @match *://dto.to/*
  13. // @match *://fto.to/*
  14. // @match *://hto.to/*
  15. // @match *://jto.to/*
  16. // @match *://lto.to/*
  17. // @match *://mto.to/*
  18. // @match *://nto.to/*
  19. // @match *://vto.to/*
  20. // @match *://wto.to/*
  21. // @match *://xto.to/*
  22. // @match *://yto.to/*
  23. // @match *://vba.to/*
  24. // @match *://wba.to/*
  25. // @match *://xba.to/*
  26. // @match *://yba.to/*
  27. // @match *://zba.to/*
  28. // @match *://bato.ac/*
  29. // @match *://bato.bz/*
  30. // @match *://bato.cc/*
  31. // @match *://bato.cx/*
  32. // @match *://bato.id/*
  33. // @match *://bato.pw/*
  34. // @match *://bato.sh/*
  35. // @match *://bato.vc/*
  36. // @match *://bato.day/*
  37. // @match *://bato.red/*
  38. // @match *://bato.run/*
  39. // @match *://batoto.in/*
  40. // @match *://batoto.tv/*
  41. // @match *://batotoo.com/*
  42. // @match *://batotwo.com/*
  43. // @match *://battwo.com/*
  44. // @match *://xbato.com/*
  45. // @match *://xbato.net/*
  46. // @match *://xbato.org/*
  47. // @match *://zbato.com/*
  48. // @match *://zbato.net/*
  49. // @match *://zbato.org/*
  50. // @match *://batpub.com/*
  51. // @match *://batread.com/*
  52. // @match *://comiko.net/*
  53. // @match *://comiko.org/*
  54. // @match *://mangatoto.com/*
  55. // @match *://mangatoto.net/*
  56. // @match *://mangatoto.org/*
  57. // @match *://batocomic.com/*
  58. // @match *://batocomic.net/*
  59. // @match *://batocomic.org/*
  60. // @match *://readtoto.com/*
  61. // @match *://readtoto.net/*
  62. // @match *://readtoto.org/*
  63. // @match *://kuku.to/*
  64. // @match *://okok.to/*
  65. // @match *://ruru.to/*
  66. // @match *://xdxd.to/*
  67. // ==/UserScript==
  68.  
  69. /*
  70. ===================== Changelog =====================
  71. v3.6 – Unified milestone release.
  72. Incorporates final unified core architecture, mirror alignment cleanup,
  73. Firefox-safe execution model, conditional v1.9.1 hybrid recovery logic,
  74. full mirror coverage, optional non-intrusive Pastebin updater, and removal
  75. of always-on retry behavior. Represents the stabilized convergence point
  76. of v3.x development.
  77.  
  78. v3.0 – Major refactor experiments and hybrid architecture exploration.
  79. v2.6 – Hybrid engine + updater attempts.
  80. v2.3 – Stability fixes.
  81. v2.0 – Hybrid concept introduced.
  82. v1.9.1– Hybrid update integrating fixes from redditor “mindlesstourist3”
  83. (host rotation, retry/backoff, broken-image detection).
  84. v1.9 – Metadata fixes, stronger attribute handling, improved srcset support.
  85. v1.8 – bato.si + mirror expansion.
  86. v1.7 – Dynamic DOM handling.
  87. v1.6 – Observer optimizations.
  88. v1.5 – Community mirror expansion.
  89. v1.4 – Critical banner fix (property-level img.src).
  90. v1.3 – MutationObserver introduced.
  91. v1.2 – Attribute safety.
  92. v1.1 – Minor fixes.
  93. v1.0 – Initial k→n replacement.
  94. ====================================================
  95. */
  96.  
  97. (function () {
  98. 'use strict';
  99.  
  100. if (window.__BTFX_LOADED__) return;
  101. window.__BTFX_LOADED__ = true;
  102.  
  103. const VERSION = '3.6';
  104. const UPDATE_URL = 'https://pastebin.com/raw/c0mBHwtH';
  105. const HOST_RE = /(^|\/\/)k(\d*\.)/i;
  106. const STATE = Symbol('BTFX_STATE');
  107.  
  108. /* ---------------- Unified core ---------------- */
  109.  
  110. function fixURL(u) {
  111. return typeof u === 'string' && HOST_RE.test(u)
  112. ? u.replace(HOST_RE, '$1n$2')
  113. : null;
  114. }
  115.  
  116. function fixSrcset(v) {
  117. if (!v || !HOST_RE.test(v)) return null;
  118. return v.split(',').map(p => {
  119. const s = p.trim().split(/\s+/);
  120. s[0] = fixURL(s[0]) || s[0];
  121. return s.join(' ');
  122. }).join(', ');
  123. }
  124.  
  125. function rewrite(img) {
  126. let touched = false;
  127. ['src','data-src','data-original','srcset','data-srcset'].forEach(a => {
  128. const v = img.getAttribute(a);
  129. if (!v) return;
  130. const f = a.includes('srcset') ? fixSrcset(v) : fixURL(v);
  131. if (f && f !== v) {
  132. img.setAttribute(a, f);
  133. touched = true;
  134. }
  135. });
  136.  
  137. if (img.src && HOST_RE.test(img.src)) {
  138. const f = fixURL(img.src);
  139. if (f) { img.src = f; touched = true; }
  140. }
  141.  
  142. if (touched) img.referrerPolicy = 'no-referrer';
  143. }
  144.  
  145. /* ---------------- Hybrid recovery ---------------- */
  146.  
  147. function recover(img) {
  148. if (img[STATE]) return;
  149. img[STATE] = { tries: 0 };
  150.  
  151. const max = 12;
  152.  
  153. function rotate() {
  154. if (++img[STATE].tries > max) cleanup();
  155. img.src = img.src.replace(/(\d+)(\.)/, (_, n, d) =>
  156. String((+n + 1) % max).padStart(2, '0') + d
  157. );
  158. }
  159.  
  160. function cleanup() {
  161. img.removeEventListener('error', onErr);
  162. img.removeEventListener('load', onLoad);
  163. }
  164.  
  165. const onErr = () => setTimeout(rotate, img[STATE].tries * 600);
  166. const onLoad = () => cleanup();
  167.  
  168. img.addEventListener('error', onErr);
  169. img.addEventListener('load', onLoad);
  170. }
  171.  
  172. /* ---------------- Pipeline ---------------- */
  173.  
  174. function handle(img) {
  175. rewrite(img);
  176. if (!img.complete || img.naturalWidth === 0) recover(img);
  177. }
  178.  
  179. function scan(root = document) {
  180. root.querySelectorAll('img').forEach(handle);
  181. }
  182.  
  183. scan();
  184. document.addEventListener('DOMContentLoaded', () => scan());
  185. window.addEventListener('load', () => scan());
  186.  
  187. const mo = new MutationObserver(ms => {
  188. ms.forEach(m => {
  189. if (m.type === 'childList') {
  190. m.addedNodes.forEach(n => n.nodeType === 1 && scan(n));
  191. }
  192. });
  193. });
  194.  
  195. mo.observe(document.documentElement, { childList: true, subtree: true });
  196.  
  197. })();
Advertisement
Add Comment
Please, Sign In to add comment