chore: beta release v0.5.0-beta
- Bump version to 0.5.0-beta - Add Apache-2.0 LICENSE (official text) + NOTICE - Add Docker support: multi-stage Dockerfile + docker-compose * non-root user, tini PID 1, gunicorn + uvicorn workers * healthcheck, OCI labels, persistent /data volume - Add GitHub Actions CI (lint/import-check + Docker smoke-test) - Backend polish: * modern lifespan handler (replaces deprecated on_event) * explicit sort validation (400 instead of 500) * title min_length=1 schema validation * configurable data dir + http timeout via env * avg_rating helper extracted (DRY) - Frontend polish: * beta badge in title, footer with live version * loading spinner on initial fetch * updated README, badges, config table, roadmap
This commit is contained in:
+11
-9
@@ -1,4 +1,5 @@
|
||||
"""Datenbank-Operationen (CRUD) für WatchStack."""
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Optional, Sequence
|
||||
@@ -166,23 +167,24 @@ def bump_progress(db: Session, media: models.Media, payload: schemas.ProgressUpd
|
||||
|
||||
# ---------- Statistik --------------------------------------------------------
|
||||
|
||||
def _avg(values: Sequence[Optional[float]]) -> Optional[float]:
|
||||
"""Mittelwert ohne None, gerundet auf 2 Stellen; None wenn leer."""
|
||||
rated = [v for v in values if v is not None]
|
||||
if not rated:
|
||||
return None
|
||||
return round(sum(rated) / len(rated), 2)
|
||||
|
||||
|
||||
def stats(db: Session) -> schemas.StatsResponse:
|
||||
def per_kind(kind: str) -> schemas.StatsPerKind:
|
||||
items = db.scalars(select(models.Media).where(models.Media.kind == kind)).all()
|
||||
total = len(items)
|
||||
avg = (
|
||||
round(sum(m.rating for m in items if m.rating is not None) /
|
||||
max(1, sum(1 for m in items if m.rating is not None)), 2)
|
||||
if any(m.rating is not None for m in items)
|
||||
else None
|
||||
)
|
||||
by_status: dict[str, int] = {s: 0 for s in models.STATUS_VALUES}
|
||||
for m in items:
|
||||
by_status[m.status] = by_status.get(m.status, 0) + 1
|
||||
return schemas.StatsPerKind(
|
||||
kind=kind,
|
||||
total=total,
|
||||
avg_rating=avg,
|
||||
total=len(items),
|
||||
avg_rating=_avg([m.rating for m in items]),
|
||||
by_status=[schemas.StatsBucket(status=k, count=v) for k, v in by_status.items()],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user