La ficha del manga incluye la info de la obra, menú lateral y banners reescalados
- Ficha e Info son una sola página: banner, puntuaciones, sinopsis, obras relacionadas y recomendaciones. - La info se guarda una vez por manga para todos los usuarios y se actualiza en segundo plano; los mangas seguidos la mantienen al día solos. Si una fuente falla, se conserva lo guardado. - Menú lateral (⋯) con seguir, listas, recortes, otras fuentes, descargas y datos de la obra. - Banners reescalados con Real-ESRGAN; si la obra no tiene, se usa un recorte del propio usuario. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+14
-8
@@ -1,6 +1,7 @@
|
||||
// Portadas en HD: cada portada que se sirve (de la fuente o la cover.jpg de una descarga) se encola para
|
||||
// reescalarla con Real-ESRGAN (×4 si es pequeña, ×2 si no). Mientras tanto se sirve la original con
|
||||
// caché corta; en cuanto existe la versión HD se sirve esa. Caché en <DATA_DIR>/covers/<hash>.webp.
|
||||
// Los banners de la ficha pasan por lo mismo, pero se reescalan siempre: se ven a todo el ancho de la pantalla.
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
@@ -11,6 +12,7 @@ const MAX_QUEUE = 300
|
||||
const X4_MAX_SIDE = 400
|
||||
const MAX_SIDE = 1600 // más grande ya no hace falta reescalarla
|
||||
const WEBP_QUALITY = 88
|
||||
const BANNER_X4_MAX_WIDTH = 1000
|
||||
|
||||
// Ancho/alto de un JPEG, PNG o WebP sin decodificarlo (null si no se reconoce).
|
||||
export function imageSize(b) {
|
||||
@@ -53,23 +55,26 @@ export function setupCovers({ DATA_DIR, upscale }) {
|
||||
return true
|
||||
}
|
||||
// Cabecera de caché para la original mientras no hay HD (corta, para que el navegador pida luego la HD).
|
||||
const pendingCache = () => (upscale.available() ? 'private, max-age=300' : 'private, max-age=604800, immutable')
|
||||
// Un banner no se guarda: en la siguiente visita ya se ve el reescalado.
|
||||
const pendingCache = (banner = false) => (!upscale.available() ? 'private, max-age=604800, immutable' : banner ? 'no-store' : 'private, max-age=300')
|
||||
|
||||
function enqueue(key, buf) {
|
||||
if (!upscale.available() || pending.has(key) || failed.has(key) || queue.length >= MAX_QUEUE || fs.existsSync(fileOf(key))) return
|
||||
// ¿Falta generar esta imagen? (para no descargarla si no hace falta)
|
||||
const wants = key => upscale.available() && !pending.has(key) && !failed.has(key) && queue.length < MAX_QUEUE && !fs.existsSync(fileOf(key))
|
||||
function enqueue(key, buf, banner = false) {
|
||||
if (!wants(key)) return
|
||||
pending.add(key)
|
||||
queue.push({ key, buf })
|
||||
queue.push({ key, buf, banner })
|
||||
pump()
|
||||
}
|
||||
|
||||
async function processOne({ key, buf }) {
|
||||
async function processOne({ key, buf, banner }) {
|
||||
const size = imageSize(buf)
|
||||
if (!size) throw new Error('formato no reconocido')
|
||||
const work = fs.mkdtempSync(path.join(os.tmpdir(), 'cover-'))
|
||||
try {
|
||||
const out = path.join(work, 'out.png')
|
||||
const tmp = `${fileOf(key)}.tmp`
|
||||
if (Math.max(size.w, size.h) > MAX_SIDE) {
|
||||
if (!banner && Math.max(size.w, size.h) > MAX_SIDE) {
|
||||
// Ya es grande: solo se recomprime para no volver a intentarlo.
|
||||
const inp = path.join(work, `in.${size.type}`)
|
||||
fs.writeFileSync(inp, buf)
|
||||
@@ -78,7 +83,8 @@ export function setupCovers({ DATA_DIR, upscale }) {
|
||||
} else {
|
||||
const inp = path.join(work, `in.${size.type}`)
|
||||
fs.writeFileSync(inp, buf)
|
||||
const scale = Math.max(size.w, size.h) <= X4_MAX_SIDE && fs.existsSync(path.join(MODELS, `${MODEL}-x4.bin`)) ? 4 : 2
|
||||
const small = banner ? size.w < BANNER_X4_MAX_WIDTH : Math.max(size.w, size.h) <= X4_MAX_SIDE
|
||||
const scale = small && fs.existsSync(path.join(MODELS, `${MODEL}-x4.bin`)) ? 4 : 2
|
||||
await run(BIN, ['-i', inp, '-o', out, '-m', MODELS, '-n', MODEL, '-s', String(scale), '-f', 'png'])
|
||||
await run('cwebp', ['-quiet', '-q', String(WEBP_QUALITY), '-m', '4', '-mt', out, '-o', tmp])
|
||||
}
|
||||
@@ -105,5 +111,5 @@ export function setupCovers({ DATA_DIR, upscale }) {
|
||||
}
|
||||
}
|
||||
|
||||
return { sendCached, enqueue, pendingCache, pendingCount: () => pending.size }
|
||||
return { sendCached, wants, enqueue, pendingCache, pendingCount: () => pending.size }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user