NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name WTL-LAB Parser // @description Mejoras para la legibilidad de los capítulos // @version 2.0.24a // @copyright 2024, trystan4861 (https://openuserjs.org/users/trystan4861) // @license MIT // @author trystan4861 // @namespace https://wtr-lab.com/ // @match https://wtr-lab.com/* // @icon https://wtr-lab.com/images/favicon.png // @homepageURL https://openuserjs.org/scripts/trystan4861/WTL-LAB_Parser // @updateURL https://openuserjs.org/meta/trystan4861/WTL-LAB_Parser.meta.js // @downloadURL https://openuserjs.org/install/trystan4861/WTL-LAB_Parser.user.js // @grant GM_addStyle // ==/UserScript== // ==OpenUserJS== // @author trystan4861 // ==/OpenUserJS== /* jshint esversion: 11 */ /* Change Log: 2.0.23 - 27/12/2024: * New: Procesar multiples comas 2.0.22 - 24/12/2024: * Refactor * Fix: procear millones con decimales 2.0.21 - 24/12/2024: * New: Añadir comprobador de novela para ejecutar parseE y parseW 2.0.20 - 24/12/2024: * Fix: Arreglar fallo en localeNumber que formateaba erróneamente la parte decimal agregando separadores de miles cuando no debía 2.0.19 - 23/12/2024: * New: Procear magnitudes de millones y de mil millones 2.0.18 - 23/12/2024: * Fix: Activar el script cuando no se entra directamene a un capítulo y quedarse en espera hasta detectar un capítulo debido a la forma en que funciona wtr-lab.com para cargar el contenido de las páginas por ajax 2.0.17 - 20/12/2024 * Minor changes 2.0.16 - 16/12/2024: * Fix: Error en localeNumber */ (function () { 'use strict'; const getNovelName = () => (window.location.href.match(/serie-\d+\/([\w-]+)\/chapter-\d+/) || [])[1] || null; const procesarComas = s => s.replace(/\b(\d+(?:,[0-9]{1,2}){2,})\b/g, match => match.replace(/,/g, ', ')); const procesarPuntos = s => s.replace(/\b(\d+(?:\.\d+){2,})\b/g, match => match.replace(/\./g, ', ')); const fixNumber = s => /^\d+\.\d{2}\.000$/.test(s) ? localeNumber(Number(s.replace(/\./g, '').slice(0, -3)) * 10**2) : s; const localeNumber = s => String(s).replace(/(\d+)([,.]\d+)?/g, (_, intPart, decimalPart) => intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ".") + (decimalPart || "")); const parseW = s => s.replace(/(\d+[\.,]?\d*)[wW](?=\b|\.|\+|$)/g, (_, n) => `${parseFloat(n.replace(',', '.')) * 10**4}` ); const parseE = s => s.replace(/(\d+([,|\.]\d+)?)[eE](?![a-zA-Z])/g, (_, n) => parseFloat(n.replace(',', '.') * 10**8)); const tipoFiltro=s=>config.filtros.toBreak.some(f => s.includes(f)) ? "break" : config.filtros.toDelete.some(f => s.includes(f)) ? "delete" : null; const parseBillions = texto => texto.replace(/(\d+(?:[,.]\d+)?)(\s*(mil millones))/gi, (_, n, t) => parseFloat(n.replace(',', '.') * 10**3).toFixed(0) + " millones"); const parseDecimalMillions = (s) => s.replace(/(\d+),(\d+)\s+millones de\s+(.*)$/, (_, entero, decimales, unidad) => `${parseInt(entero + decimales.padEnd(6, '0'), 10)} ${unidad}`); const parseMillions = (s) => s.replace(/(\d+),(\d+)\s+millones/, (_, entero, decimales) => localeNumber(entero + decimales.padEnd(6, '0'), 10)); const quitarEspacioEntreNumeroYW = texto => texto.replace(/(\d+(,\d+)?)(\s)W(?![a-zA-Z0-9])/g, (_, p1) => p1 + "W"); const getChapterTitle=()=>document.querySelector(".chapter-title")?.innerText; const sustituirPalabraSwap = s => s.replace(new RegExp(`(\\w+)\\s+(${Object.keys(store.transforms).join("|")})`, "g"), (_, palabra, termino) => `${store.transforms[termino]} ${palabra}`); const sustituirPalabra = s => s.replace(new RegExp(`^(${Object.keys(store.sustitutes).join("|")})(\\W.*)?$`), (_, base, sufijo) => (store.sustitutes[base] || base) + (sufijo || "")); const config = { delay: 10000, estilos: { fondoResaltado: "yellow", fondoMarcado: "red", textoResaltado: "black", textoMarcado: "black", }, filtros: { toHideEqual: [".", "Xinbiquge"], toHideIncludes: [".c0m", ".com"], toBreak: ["la versión web es lento", "En el vasto universo, el nacimiento"], toDelete: ["window._taboola", "Recordatorio: si descubre que hacer clic"], }, parseW: ["a-miracle-at-the-beginning"], parseE: ["a-miracle-at-the-beginning"], novels: { "a-miracle-at-the-beginning": { p:[ procesarPuntos, quitarEspacioEntreNumeroYW, parseBillions, parseDecimalMillions, parseMillions, procesarComas, ], span:[ parseW, parseE, ], } }, }; const store = { ultimaPalabraVisible: null, scrollTimeout: null, direccionScroll: "down", ultimaPosicionScroll: window.scrollY, esPrimeraVez: true, mutationTimeout: null, ultimaPalabraMarcada: null, chapterTitle: "", sustitutes: { RPDC: "corte", Yelvzong: "Yelu Zong", Yeluzong: "Yelu Zong", Yelv: "Yelu", Chase: "Perseguidle", "【Consejo": "【Anuncio", " 】":"】", }, transforms: { Shangshu: "Ministro", }, }; GM_addStyle(` .resaltado { background-color: ${config.estilos.fondoResaltado}; color: ${config.estilos.textoResaltado}; } .marked { background-color: ${config.estilos.fondoMarcado}; color: ${config.estilos.textoMarcado}; } `); function check2Hide(span) { const { toHideIncludes, toHideEqual } = config.filtros; if (toHideIncludes.some(t => span.textContent.toLowerCase().includes(t)) || toHideEqual.some(t => span.textContent.trim() === t)) { span.style.display = "none"; return true; } return false; } function detectarDireccionScroll() { const posicionActual = window.scrollY; store.direccionScroll = posicionActual > store.ultimaPosicionScroll ? "down" : "up"; store.ultimaPosicionScroll = posicionActual; } const parseAll = s => { const match = window.location.href.match(/serie-\d+\/([\w-]+)\/chapter-\d+/); if (match) { const [_, key] = match; if (config.parseE.includes(key)) s = parseE(s); if (config.parseW.includes(key)) s = parseW(s); } return sustituirPalabra(localeNumber(fixNumber(s))); }; function getSpansFrom(parrafo) { parrafo.innerHTML = parrafo.textContent.trim() .split(" ") .map(palabra => `<span class="marcable">${parseAll(palabra)} </span>`) .join(""); return Array.from(parrafo.querySelectorAll("span.marcable")); } function marcarSpan(span) { if (store.ultimaPalabraMarcada) { store.ultimaPalabraMarcada.element.classList.remove("marked"); if (store.ultimaPalabraMarcada.element === span) { store.ultimaPalabraMarcada = null; return; } } span.classList.add("marked"); store.ultimaPalabraMarcada = { element: span, tiempoMarcado: Date.now() }; } function main() { if (!store.chapterTitle) { store.chapterTitle = getChapterTitle(); } if (!store.chapterTitle) return; store.esPrimeraVez = true; store.ultimaPalabraVisible = null; let hideAll = false; document.querySelectorAll("p").forEach(parrafo => { const filtro = tipoFiltro(parrafo.textContent); hideAll = hideAll || filtro === "break"; if (hideAll || filtro === "delete") { parrafo.style.display = "none"; return; } parrafo.textContent = parrafo.textContent.trim(); parrafo.textContent = config.novels[getNovelName()]?.p.reduce((t, f) => f(t), parrafo.textContent) || parrafo.textContent; getSpansFrom(parrafo).forEach(span => { if (check2Hide(span)) return; observer.observe(span); span.addEventListener("click", () => marcarSpan(span)); }); }); if (store.ultimaPalabraMarcada && document.contains(store.ultimaPalabraMarcada.element)) { store.ultimaPalabraMarcada.element.classList.add("marked"); } } const doUltimaVisible =(ultimaVisible)=>{ store.ultimaPalabraVisible?.classList.remove("resaltado"); ultimaVisible.classList.add("resaltado"); store.ultimaPalabraVisible = ultimaVisible; } const observer = new IntersectionObserver((entradas) => { const ultimaVisible = entradas.filter(e => e.isIntersecting).at(-1)?.target; if (!ultimaVisible) return; if (store.esPrimeraVez) { doUltimaVisible(ultimaVisible); store.esPrimeraVez = false; return; } if (store.direccionScroll === "down" && ultimaVisible !== store.ultimaPalabraVisible) { clearTimeout(store.scrollTimeout); store.scrollTimeout = setTimeout(() => doUltimaVisible(ultimaVisible), config.delay); } }, { threshold: 1.0 }); const mutationObserver = new MutationObserver(() => { const nuevoTitulo = getChapterTitle(); if (nuevoTitulo !== store.chapterTitle) { store.chapterTitle = nuevoTitulo; clearTimeout(store.mutationTimeout); store.mutationTimeout = setTimeout(main, 100); } }); const check=()=>{ if (getChapterTitle()) { console.log("CHECK WTR"); mutationObserver.observe(document.body, { childList: true, subtree: true }); window.addEventListener("scroll", detectarDireccionScroll); window.addEventListener("load", main); } else{ setTimeout(check,2000); } } check(); })();