feat: auto-téléchargement par catégorie avec souscription persistante
Docker / docker (push) Has been cancelled
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:
+52
-2
@@ -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"}))
|
||||
|
||||
Reference in New Issue
Block a user