Reescalado HD, ficha reorganizada y mejoras del lector

- Reescalado HD con Real-ESRGAN (ncnn-vulkan, GPU por /dev/dri): cola persistente,
  todo lo pendiente, un rango o capítulos elegidos en la lista, con estimación de tiempo.
  La versión HD va a <carpeta>/.hd/ sin tocar el original; marca HD en la lista de
  capítulos y casilla "Versión HD" en el lector.
- Imagen Debian slim (glibc + Mesa Vulkan + cwebp); compose con /dev/dri y RENDER_GID.
- Ficha: acciones principales + menú ⋯, panel "Biblioteca local" (copia local y HD),
  idioma junto a la lista de capítulos.
- Lector: la barra de progreso avanza de derecha a izquierda en der → izq; botón rápido
  páginas ⇄ vertical; en vertical "Ajustar alto" y "Separar páginas" para mangas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 10:51:29 -06:00
co-authored by Claude Opus 5.5
parent 9e9139f43a
commit bc84a9f6fe
10 changed files with 645 additions and 64 deletions
+11 -5
View File
@@ -98,6 +98,15 @@ export function imageType(name) {
return { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', webp: 'image/webp', gif: 'image/gif', avif: 'image/avif' }[ext] || 'application/octet-stream'
}
// Lee una entrada completa del CBZ a memoria.
export function readCbzEntry(file, entry) {
if (entry.method !== 0 && entry.method !== 8) throw new Error(`Compresión ZIP no soportada (${entry.method})`)
const fd = fs.openSync(file, 'r')
const buf = Buffer.alloc(entry.size)
try { fs.readSync(fd, buf, 0, entry.size, entry.start) } finally { fs.closeSync(fd) }
return entry.method === 8 ? zlib.inflateRawSync(buf) : buf
}
// Envía una entrada del CBZ por la respuesta HTTP.
export function sendCbzEntry(res, file, entry) {
const headers = { 'Content-Type': imageType(entry.name), 'Cache-Control': 'private, max-age=604800' }
@@ -106,10 +115,7 @@ export function sendCbzEntry(res, file, entry) {
fs.createReadStream(file, { start: entry.start, end: entry.start + entry.size - 1 }).pipe(res)
return
}
if (entry.method !== 8) throw new Error(`Compresión ZIP no soportada (${entry.method})`)
const fd = fs.openSync(file, 'r')
const buf = Buffer.alloc(entry.size)
try { fs.readSync(fd, buf, 0, entry.size, entry.start) } finally { fs.closeSync(fd) }
const data = readCbzEntry(file, entry)
res.writeHead(200, headers)
res.end(zlib.inflateRawSync(buf))
res.end(data)
}