import fs from "fs" import path from "path" import { get } from "./settings" const COVERS_DIR = process.env.COVERS_DIR || path.join(process.cwd(), "data", "covers") function ensureDir() { fs.mkdirSync(COVERS_DIR, { recursive: true }) } function extFromContentType(ct: string | null): string { if (!ct) return ".jpg" const m = ct.match(/image\/(\w+)/) if (!m) return ".jpg" const exts: Record = { jpeg: ".jpg", png: ".png", webp: ".webp", gif: ".gif", } return exts[m[1]] || ".jpg" } // Descarga la portada DIRECTAMENTE del upstream (API_BASE_URL), con la misma // API key que usa el resto de la app. NO pasa por el proxy /api/proxy/* (que el // middleware protege), evitando el redirect a /login que guardaba HTML como portada. export async function cacheCover(gid: string): Promise { ensureDir() try { const apiBase = get("API_BASE_URL", "http://127.0.0.1:8080/api/v1") const apiKey = get("API_KEY") const headers: Record = {} if (apiKey) headers["X-API-Key"] = apiKey const res = await fetch(`${apiBase}/galleries/${gid}/cover`, { headers, signal: AbortSignal.timeout(15000), }) if (!res.ok) return null const buffer = Buffer.from(await res.arrayBuffer()) const ext = extFromContentType(res.headers.get("content-type")) const filePath = path.join(COVERS_DIR, `${gid}${ext}`) fs.writeFileSync(filePath, buffer) return filePath } catch { return null } } export function getCoverPath(gid: string): string | null { ensureDir() const files = fs.readdirSync(COVERS_DIR).filter((f) => f.startsWith(`${gid}.`)) if (files.length === 0) return null return path.join(COVERS_DIR, files[0]) } export function getCoverContentType(gid: string): string { const fp = getCoverPath(gid) if (!fp) return "image/jpeg" const ext = path.extname(fp).toLowerCase() const m: Record = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".webp": "image/webp", ".gif": "image/gif", } return m[ext] || "image/jpeg" } export function deleteCover(gid: string): void { const fp = getCoverPath(gid) if (fp) fs.unlinkSync(fp) }