Enhance PVideoDl with finished_at tracking for downloads and UI updates. Added finished_at field to Download model, updated storage to handle legacy databases, and improved frontend to display recent downloads. Refactored scripts for better clarity and error handling.

This commit is contained in:
Leonid Pershin
2026-06-19 16:27:20 +03:00
parent 303de2b26c
commit 3e47e95fc4
14 changed files with 316 additions and 126 deletions
+42
View File
@@ -1,6 +1,8 @@
import tempfile
from datetime import datetime, timezone
from pathlib import Path
import aiosqlite
import pytest
from app.core.storage import SqliteStorage
@@ -57,6 +59,45 @@ async def test_delete(storage: SqliteStorage):
assert await storage.get(d.id) is None
async def test_finished_at_roundtrip(storage: SqliteStorage):
d = Download(url="https://example.com/a.zip")
await storage.create(d)
assert (await storage.get(d.id)).finished_at is None
ts = datetime.now(timezone.utc)
snap = await storage.update(d.id, status=DownloadStatus.DONE, finished_at=ts)
assert snap is not None and snap.finished_at == ts
async def test_migrates_legacy_db_without_finished_at():
# БД, созданная до появления колонки finished_at.
path = Path(tempfile.mkdtemp()) / "legacy.db"
db = await aiosqlite.connect(path)
await db.execute(
"""
CREATE TABLE downloads (
id TEXT PRIMARY KEY, url TEXT NOT NULL, filename TEXT,
status TEXT NOT NULL, progress REAL NOT NULL DEFAULT 0,
size_bytes INTEGER, downloaded_bytes INTEGER NOT NULL DEFAULT 0,
speed REAL, eta REAL, error TEXT, created_at TEXT NOT NULL
)
"""
)
await db.execute(
"INSERT INTO downloads (id, url, status, created_at) VALUES (?, ?, ?, ?)",
("x1", "https://e.com/a.zip", "done", datetime.now(timezone.utc).isoformat()),
)
await db.commit()
await db.close()
st = SqliteStorage(path)
await st.init() # должен добавить колонку, не уронив существующие данные
got = await st.get("x1")
assert got is not None and got.status == DownloadStatus.DONE
assert got.finished_at is None
await st.close()
async def test_downloading_marked_failed_on_init():
path = Path(tempfile.mkdtemp()) / "test.db"
st = SqliteStorage(path)
@@ -69,4 +110,5 @@ async def test_downloading_marked_failed_on_init():
await st2.init() # должен пометить "качающиеся" записи как FAILED
got = await st2.get(d.id)
assert got is not None and got.status == DownloadStatus.FAILED
assert got.finished_at is not None # прерванная загрузка тоже «завершилась»
await st2.close()