feat: auto-téléchargement par catégorie avec souscription persistante
Docker / docker (push) Has been cancelled

- Bouton ⬇ sur chaque pill de catégorie pour activer/désactiver l'auto-DL
- Souscriptions sauvegardées en SQLite (table auto_dl_categories)
- Boucle background toutes les AUTO_DL_INTERVAL secondes (défaut 1h)
- Déduplication via already_enqueued() (évite re-queue si déjà queued/done)
- POST /api/auto-dl/check pour déclencher un check immédiat
- GET/POST/DELETE /api/auto-dl/{category} pour gérer les souscriptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dev
2026-05-02 19:23:57 +02:00
parent f07352bd04
commit 189b65bd6d
5 changed files with 220 additions and 10 deletions
+52 -2
View File
@@ -1,3 +1,4 @@
import asyncio
import re
import sqlite3
import threading
@@ -103,11 +104,48 @@ class DownloadManager:
error TEXT
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS auto_dl_categories (
category TEXT PRIMARY KEY,
added_at TEXT NOT NULL
)
""")
# ------------------------------------------------------------------ public
def enqueue(self, url: str, title: str, subtitle: str, year: int | None,
category: str, bg: BackgroundTasks) -> str:
def get_watched_categories(self) -> list[str]:
with _db() as conn:
rows = conn.execute(
"SELECT category FROM auto_dl_categories ORDER BY added_at"
).fetchall()
return [r["category"] for r in rows]
def watch_category(self, category: str):
with _db() as conn:
conn.execute(
"INSERT OR IGNORE INTO auto_dl_categories (category, added_at) VALUES (?,?)",
(category, datetime.now().isoformat()),
)
def unwatch_category(self, category: str):
with _db() as conn:
conn.execute("DELETE FROM auto_dl_categories WHERE category=?", (category,))
def already_enqueued(self, url: str) -> bool:
with _db() as conn:
row = conn.execute(
"SELECT id FROM downloads WHERE url=? AND state != 'error' LIMIT 1", (url,)
).fetchone()
return row is not None
def already_downloaded(self, url: str) -> bool:
with _db() as conn:
row = conn.execute(
"SELECT id FROM downloads WHERE url=? AND state='done' LIMIT 1", (url,)
).fetchone()
return row is not None
def _insert_queued(self, url: str, title: str) -> str:
dl_id = str(uuid.uuid4())
now = datetime.now().isoformat()
with _db() as conn:
@@ -117,9 +155,21 @@ class DownloadManager:
)
with self._lock:
self._active[dl_id] = {"state": "queued", "progress": 0, "title": title}
return dl_id
def enqueue(self, url: str, title: str, subtitle: str, year: int | None,
category: str, bg: BackgroundTasks) -> str:
dl_id = self._insert_queued(url, title)
bg.add_task(self._run, dl_id, url, title, subtitle, year, category)
return dl_id
async def enqueue_direct(self, url: str, title: str, subtitle: str,
year: int | None, category: str) -> str:
dl_id = self._insert_queued(url, title)
loop = asyncio.get_running_loop()
loop.run_in_executor(None, self._run, dl_id, url, title, subtitle, year, category)
return dl_id
def status(self, dl_id: str) -> dict:
with self._lock:
return dict(self._active.get(dl_id, {"state": "unknown"}))