add route to check state of latest IMDb movie import

This commit is contained in:
ducklet 2021-07-22 00:05:02 +02:00
parent 1fd592cb1d
commit fe5db535a9
4 changed files with 87 additions and 26 deletions

View file

@ -9,6 +9,7 @@ from databases import Database
from . import config
from .models import (
Movie,
Progress,
Rating,
User,
asplain,
@ -125,34 +126,32 @@ async def apply_db_patches(db: Database):
await db.execute("vacuum")
async def get_import_progress() -> float:
"""Return the current import progress percentage.
The progress will be a value from 0 to 100. If the value is 100, the last
import was completed successfully and no import is currently running.
"""
query = "SELECT state FROM progress WHERE id='import_imdb'"
state = await shared_connection().fetch_val(query)
return float(state or 100)
async def get_import_progress() -> Optional[Progress]:
"""Return the latest import progress."""
return await get(Progress, type="import-imdb-movies", order_by="started DESC")
async def set_import_progress(progress: float):
async def set_import_progress(progress: float) -> Progress:
"""Set the current import progress percentage."""
progress = min(max(0.0, progress), 100.0) # clamp to 0 <= progress <= 100
values = {"id": "import_imdb"}
current = await get_import_progress()
is_update = current and current.stopped is None
if not current or not is_update:
current = Progress(type="import-imdb-movies")
current.state = f"{progress:.2f}"
if progress >= 100:
query = "DELETE FROM progress WHERE id=:id"
else:
query = """
INSERT INTO progress(id, state, started)
VALUES (:id, :state, :started)
ON CONFLICT DO UPDATE SET state=excluded.state
"""
values.update({"state": f"{progress:.2f}", "started": utcnow().isoformat()})
current.stopped = utcnow().isoformat()
await shared_connection().execute(query=query, values=values)
if is_update:
await update(current)
else:
await add(current)
return current
def shared_connection() -> Database:
@ -183,7 +182,9 @@ async def add(item):
ModelType = TypeVar("ModelType")
async def get(model: Type[ModelType], **kwds) -> Optional[ModelType]:
async def get(
model: Type[ModelType], *, order_by: str = None, **kwds
) -> Optional[ModelType]:
values = {k: v for k, v in kwds.items() if v is not None}
if not values:
return
@ -191,6 +192,8 @@ async def get(model: Type[ModelType], **kwds) -> Optional[ModelType]:
fields_ = ", ".join(f.name for f in fields(model))
cond = " AND ".join(f"{k}=:{k}" for k in values)
query = f"SELECT {fields_} FROM {model._table} WHERE {cond}"
if order_by:
query += f" ORDER BY {order_by}"
row = await shared_connection().fetch_one(query=query, values=values)
return fromplain(model, row) if row else None

View file

@ -140,6 +140,17 @@ def utcnow():
return datetime.now().replace(tzinfo=timezone.utc)
@dataclass
class Progress:
_table: ClassVar[str] = "progress"
id: ULID = field(default_factory=ULID)
type: str = None
state: str = None
started: datetime = field(default_factory=utcnow)
stopped: Optional[str] = None
@dataclass
class Movie:
_table: ClassVar[str] = "movies"

View file

@ -0,0 +1,24 @@
-- add IMDb vote count
CREATE TABLE _migrate_progress (
id TEXT PRIMARY KEY NOT NULL,
type TEXT NOT NULL,
state TEXT NOT NULL,
started TEXT NOT NULL,
stopped TEXT
);;
INSERT INTO _migrate_progress
SELECT
id,
'import-imdb-movies' AS type,
state,
started,
NULL AS stopped
FROM progress
WHERE true;;
DROP TABLE progress;;
ALTER TABLE _migrate_progress
RENAME TO progress;;

View file

@ -23,7 +23,7 @@ from starlette.routing import Mount, Route
from . import config, db, imdb, imdb_import
from .db import close_connection_pool, find_ratings, open_connection_pool
from .middleware.responsetime import ResponseTimeMiddleware
from .models import Group, Movie, User, asplain
from .models import Group, Movie, Progress, User, asplain
from .types import ULID
from .utils import b64encode, phc_compare, phc_scrypt
@ -198,15 +198,38 @@ async def add_movie(request):
import_lock = asyncio.Lock()
@route("/movies/_reload_imdb", methods=["GET"])
@requires(["authenticated", "admin"])
async def progress_for_load_imdb_movies(request):
progress = await db.get_import_progress()
if not progress:
return JSONResponse({"status": "No import exists."}, status_code=404)
p = asplain(progress)
percent = float(p["state"])
return JSONResponse(
{
"status": "Import is running." if percent < 100 else "Import finished.",
"progress": percent,
"started": p["started"],
"stopped": p["stopped"],
}
)
@route("/movies/_reload_imdb", methods=["POST"])
@requires(["authenticated", "admin"])
async def load_imdb_movies(request):
async with import_lock:
progress = await db.get_import_progress()
if progress < 100:
return JSONResponse(
{"status": "Import running.", "progress": progress}, status_code=409
)
if progress:
percent = float(progress.state)
if percent < 100:
return JSONResponse(
{"status": "Import is running.", "progress": percent},
status_code=409,
)
await db.set_import_progress(0)