Fuente M440, modo sin conexión (servidor sin internet y app sin servidor), cola del dispositivo en Colas y arreglo del reescalado de tiras altas
- M440 (m440.in, español): búsqueda, populares, actualizados paginados, ficha, capítulos, descargas y seguimiento. La lista de capítulos viene cifrada: la clave se saca de un script ofuscado del sitio ejecutándolo en un proceso aislado con permisos mínimos (m440-key.mjs) y se renueva sola. - Servidor sin internet (connectivity.js): se detecta en segundos; las fuentes fallan al instante, la portada muestra lo descargado en el servidor con buscador, portadas locales de respaldo, descargas y comprobaciones en pausa y reanudación automática al volver la conexión. - App sin conexión con el servidor: el service worker usa la copia guardada si el servidor no contesta en 3 s, las peticiones comprueban si el servidor sigue vivo en vez de quedarse colgadas, aviso arriba e inicio con lo guardado en el dispositivo; al volver, se reconecta sola y envía el progreso pendiente. - Colas: sección «En este dispositivo» con el guardado en curso en directo y cancelación (sin dejar capítulos a medias); también visible sin servidor. - Imágenes: el proxy y el guardado en el dispositivo reintentan con tiempo límite cuando el CDN de la fuente falla. - Reescalado HD: las páginas que superan 16383 px al reescalar (tiras de webtoon) se reducen al límite de WebP en vez de hacer fallar el capítulo. - Entidades HTML con nombre en las sinopsis; pestañas de fuentes cortas en móvil; portadas rotas con icono de respaldo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+27
-9
@@ -13,20 +13,38 @@ self.addEventListener('activate', e => {
|
||||
.then(() => self.clients.claim()))
|
||||
})
|
||||
|
||||
// Red primero (así siempre se ve la última versión) y la caché si no hay conexión.
|
||||
// Red primero (así siempre se ve la última versión) y la caché si no hay conexión. Si hay copia guardada
|
||||
// y el servidor no contesta en NET_WAIT ms (red que no llega, servidor caído o colgado), se usa la copia
|
||||
// sin esperar a que el navegador dé la conexión por perdida; la petición sigue y actualiza la caché.
|
||||
const NET_WAIT = 3000
|
||||
const DOWN_FOR = 20e3
|
||||
let downUntil = 0
|
||||
// La app distingue así una copia guardada de una respuesta real del servidor.
|
||||
async function fromCache(res) {
|
||||
const headers = new Headers(res.headers)
|
||||
headers.set('x-from-cache', '1')
|
||||
return new Response(await res.blob(), { status: res.status, statusText: res.statusText, headers })
|
||||
}
|
||||
async function networkFirst(req, cacheName, { store = true, ignoreSearch = false, fallback } = {}) {
|
||||
try {
|
||||
const res = await fetch(req)
|
||||
const cached = () => caches.match(req, { ignoreSearch, cacheName }).then(hit => hit || (fallback && caches.match(fallback)))
|
||||
const net = fetch(req).then(async res => {
|
||||
if (store && res.ok) {
|
||||
const c = await caches.open(cacheName)
|
||||
if (store === true || (await c.match(req, { ignoreSearch }))) c.put(req, res.clone())
|
||||
if (store === true || (await c.match(req, { ignoreSearch }))) await c.put(req, res.clone())
|
||||
}
|
||||
return res
|
||||
} catch (err) {
|
||||
const hit = await caches.match(req, { ignoreSearch, cacheName }) || (fallback && await caches.match(fallback))
|
||||
if (hit) return hit
|
||||
throw err
|
||||
}
|
||||
})
|
||||
net.then(() => { downUntil = 0 }, () => {})
|
||||
const hit = await cached()
|
||||
if (!hit) return net // sin copia: solo queda esperar a la red
|
||||
// Si hace poco que el servidor no contestaba, la copia directamente (la red sigue intentándolo).
|
||||
if (Date.now() < downUntil) return fromCache(hit)
|
||||
let timer
|
||||
const timeout = new Promise(r => { timer = setTimeout(() => r(null), NET_WAIT) })
|
||||
const res = await Promise.race([net.catch(() => null), timeout])
|
||||
clearTimeout(timer)
|
||||
if (!res) downUntil = Date.now() + DOWN_FOR
|
||||
return res || fromCache(hit)
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', e => {
|
||||
|
||||
Reference in New Issue
Block a user