Téléchargements : suppression par épisode et regroupement par animé
- DELETE /api/downloads/{id} (?delete_file=true pour effacer aussi le fichier)
- Événement SSE « removed » → toutes les pages ouvertes se synchronisent
- Page Téléchargements groupée par animé : groupes repliables (dépliés si
actifs), compteurs par statut, taille totale, tri par numéro d'épisode
- Actions par groupe : 🧹 retirer les terminés, ✖ annuler les actifs
- Limite de liste 200 → 2000 tâches
This commit is contained in:
@@ -69,6 +69,21 @@ async def test_stream_range(client, admin_cookies):
|
||||
)
|
||||
assert r.status_code == 416
|
||||
|
||||
async def test_delete_download(client, admin_cookies):
|
||||
path = get_settings().download_dir / "del1.mp4"
|
||||
path.write_bytes(b"data" * 100)
|
||||
cursor = await db.execute(
|
||||
"INSERT INTO downloads (source_key, video_url, page_url, title, file_path, status, "
|
||||
"total_bytes, downloaded_bytes) "
|
||||
"VALUES ('k2', 'u', 'p', 'Anime Y - E9 (VOSTFR)', 'del1.mp4', 'done', 400, 400)"
|
||||
)
|
||||
download_id = cursor.lastrowid
|
||||
r = await client.delete(f"/api/downloads/{download_id}?delete_file=true", cookies=admin_cookies)
|
||||
assert r.status_code == 200 and r.json() == {"ok": True}
|
||||
assert not path.exists()
|
||||
r = await client.delete(f"/api/downloads/{download_id}", cookies=admin_cookies)
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
async def test_admin_required(client):
|
||||
await client.post("/auth/register", data={"username": "admin2", "password": "secret123"})
|
||||
|
||||
@@ -102,3 +102,33 @@ async def test_cancel(file_server, manager):
|
||||
await dm.cancel(d["id"])
|
||||
data = await dm.get(d["id"])
|
||||
assert data["status"] in ("cancelled", "done") # course possible si déjà fini
|
||||
|
||||
async def test_delete_keeps_file(file_server, manager):
|
||||
d = await dm.enqueue(f"{file_server}/video.mp4", "http://page", "Anime X - E1 (VOSTFR)")
|
||||
data = await _wait_status(d["id"], {"done", "failed"})
|
||||
assert data["status"] == "done", data.get("error")
|
||||
path = get_settings().download_dir / data["file_path"]
|
||||
assert path.is_file()
|
||||
assert await dm.delete(d["id"]) is True
|
||||
assert await dm.get(d["id"]) is None
|
||||
assert path.is_file() # le fichier vidéo est conservé
|
||||
|
||||
|
||||
async def test_delete_with_file(file_server, manager):
|
||||
d = await dm.enqueue(f"{file_server}/video.mp4", "http://page", "Anime X - E2 (VOSTFR)")
|
||||
data = await _wait_status(d["id"], {"done", "failed"})
|
||||
path = get_settings().download_dir / data["file_path"]
|
||||
assert await dm.delete(d["id"], delete_file=True) is True
|
||||
assert await dm.get(d["id"]) is None
|
||||
assert not path.exists()
|
||||
assert await dm.delete(d["id"]) is False # déjà supprimé → introuvable
|
||||
|
||||
|
||||
async def test_delete_active(file_server, manager):
|
||||
d = await dm.enqueue(f"{file_server}/video.mp4", "http://page", "Anime X - E3")
|
||||
filename = d["file_path"]
|
||||
assert await dm.delete(d["id"]) is True
|
||||
assert await dm.get(d["id"]) is None
|
||||
download_dir = get_settings().download_dir
|
||||
assert not (download_dir / filename).exists()
|
||||
assert not (download_dir / (filename + ".part")).exists()
|
||||
|
||||
Reference in New Issue
Block a user