fix: resume interrupted downloads after container restart
Docker / docker (push) Successful in 1m22s

Store subtitle/year/category in downloads table. On startup, re-queue
any download still in queued/downloading state (reset downloading → queued).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dev
2026-05-11 14:03:31 +02:00
parent ec61b1684a
commit 09457868e4
2 changed files with 33 additions and 2 deletions
+32 -2
View File
@@ -95,6 +95,9 @@ class DownloadManager:
id TEXT PRIMARY KEY,
url TEXT NOT NULL,
title TEXT NOT NULL,
subtitle TEXT NOT NULL DEFAULT '',
year INTEGER,
category TEXT NOT NULL DEFAULT '',
filename TEXT,
state TEXT NOT NULL DEFAULT 'queued',
progress REAL DEFAULT 0,
@@ -105,6 +108,15 @@ class DownloadManager:
error TEXT
)
""")
for col, definition in [
("subtitle", "TEXT NOT NULL DEFAULT ''"),
("year", "INTEGER"),
("category", "TEXT NOT NULL DEFAULT ''"),
]:
try:
conn.execute(f"ALTER TABLE downloads ADD COLUMN {col} {definition}")
except Exception:
pass
conn.execute("""
CREATE TABLE IF NOT EXISTS auto_dl_categories (
category TEXT PRIMARY KEY,
@@ -152,14 +164,32 @@ class DownloadManager:
now = datetime.now().isoformat()
with _db() as conn:
conn.execute(
"INSERT INTO downloads (id, url, title, state, started_at) VALUES (?,?,?,'queued',?)",
(dl_id, url, title, now),
"INSERT INTO downloads (id, url, title, subtitle, year, category, state, started_at) VALUES (?,?,?,?,?,?,'queued',?)",
(dl_id, url, title, subtitle, year, category, now),
)
with self._lock:
self._active[dl_id] = {"state": "queued", "progress": 0, "title": title}
await self._queue.put((dl_id, url, title, subtitle, year, category))
return dl_id
async def resume_pending(self):
"""Re-queue downloads interrupted by a container restart."""
with _db() as conn:
rows = conn.execute(
"SELECT id, url, title, subtitle, year, category FROM downloads"
" WHERE state IN ('queued', 'downloading') ORDER BY started_at"
).fetchall()
conn.execute(
"UPDATE downloads SET state='queued', progress=0, speed='', eta=NULL"
" WHERE state='downloading'"
)
for r in rows:
with self._lock:
self._active[r["id"]] = {"state": "queued", "progress": 0, "title": r["title"]}
await self._queue.put((r["id"], r["url"], r["title"], r["subtitle"] or "", r["year"], r["category"] or ""))
if rows:
logger.info("Resumed %d pending download(s)", len(rows))
async def start_worker(self):
loop = asyncio.get_running_loop()
while True:
+1
View File
@@ -52,6 +52,7 @@ async def _auto_dl_loop():
@asynccontextmanager
async def lifespan(app: FastAPI):
await dm.resume_pending()
tasks = [
asyncio.create_task(dm.start_worker()),
asyncio.create_task(_auto_dl_loop()),