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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user