Ocultar de «Continuar leyendo» los mangas terminados salvo que haya capítulos nuevos

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 09:31:20 -06:00
co-authored by Claude Opus 5.5
parent af90d34c95
commit 9e9139f43a
2 changed files with 21 additions and 7 deletions
+16 -5
View File
@@ -107,6 +107,8 @@ CREATE TABLE IF NOT EXISTS downloaded_chapters (
CREATE INDEX IF NOT EXISTS idx_dlch_manga ON downloaded_chapters(manga_id);
`)
db.prepare('DELETE FROM sessions WHERE expires_at < ?').run(Date.now())
// finished_at: cuándo se terminó la última página del último capítulo disponible (null = en curso).
if (!db.prepare('PRAGMA table_info(progress)').all().some(c => c.name === 'finished_at')) db.exec('ALTER TABLE progress ADD COLUMN finished_at INTEGER')
// ---------- Contraseñas y sesiones ----------
function hashPassword(pw) {
@@ -796,7 +798,14 @@ async function route(req, res) {
// --- Historial ---
if (p === '/api/history' && method === 'GET') {
return json(res, 200, db.prepare('SELECT * FROM progress WHERE user_id = ? ORDER BY updated_at DESC LIMIT 200').all(user.id))
// Un manga terminado vuelve a "en curso" si después aparecieron capítulos nuevos.
const rows = db.prepare(`SELECT p.*, f.last_new_at FROM progress p
LEFT JOIN follows f ON f.user_id = p.user_id AND f.manga_id = p.manga_id AND f.active = 1
WHERE p.user_id = ? ORDER BY p.updated_at DESC LIMIT 200`).all(user.id)
return json(res, 200, rows.map(({ last_new_at, ...r }) => {
const hasNew = !!(r.finished_at && last_new_at && last_new_at > r.finished_at)
return { ...r, finished: !!r.finished_at && !hasNew, hasNew }
}))
}
if (p === '/api/progress' && method === 'POST') {
const b = await readBody(req)
@@ -804,15 +813,17 @@ async function route(req, res) {
const page = Math.max(0, Number(b.page) | 0)
const total = Math.max(0, Number(b.totalPages) | 0)
const now = Date.now()
const finishedAt = b.isLast === true && total && page >= total - 1 ? now : null
const prevPage = db.prepare('SELECT page FROM chapter_reads WHERE user_id = ? AND chapter_id = ?').get(user.id, b.chapterId)?.page
db.prepare(`INSERT INTO progress (user_id, manga_id, manga_title, cover, chapter_id, chapter_num, chapter_title, lang, page, total_pages, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
db.prepare(`INSERT INTO progress (user_id, manga_id, manga_title, cover, chapter_id, chapter_num, chapter_title, lang, page, total_pages, updated_at, finished_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (user_id, manga_id) DO UPDATE SET manga_title = excluded.manga_title, cover = excluded.cover,
chapter_id = excluded.chapter_id, chapter_num = excluded.chapter_num, chapter_title = excluded.chapter_title,
lang = excluded.lang, page = excluded.page, total_pages = excluded.total_pages, updated_at = excluded.updated_at`)
lang = excluded.lang, page = excluded.page, total_pages = excluded.total_pages, updated_at = excluded.updated_at,
finished_at = excluded.finished_at`)
.run(user.id, b.mangaId, String(b.mangaTitle || '').slice(0, 300), b.cover ? String(b.cover).slice(0, 1000) : null,
b.chapterId, b.chapterNum != null ? String(b.chapterNum) : null, String(b.chapterTitle || '').slice(0, 300),
LANG.test(b.lang || '') ? b.lang : null, page, total, now)
LANG.test(b.lang || '') ? b.lang : null, page, total, now, finishedAt)
db.prepare(`INSERT INTO chapter_reads (user_id, chapter_id, manga_id, page, total_pages, updated_at) VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT (user_id, chapter_id) DO UPDATE SET page = excluded.page, total_pages = excluded.total_pages, updated_at = excluded.updated_at`)
.run(user.id, b.chapterId, b.mangaId, page, total, now)