Files
watchlist/quivio/seed.py
T
ki 9a4909f083
CI / test (push) Has been cancelled
chore(rebrand): rename WatchStack -> Quivio
Quivio (Kofferwort aus Quire + Video) ersetzt den Arbeitstitel WatchStack.
Es ist origineller, frei auf PyPI/npm, und passt perfekt zur Doppelnatur
der App: Buecher (Quire) + Serien (Video).

Geaendert:
- Python-Paket app/ -> quivio/ (+ alle Imports angepasst)
- DB-File watchstack.db -> quivio.db
- Docker-Image: quivio:0.5.1-beta, Container-Name quivio
- Compose-Services: quivio, quivio-local
- ENV-Vars: QUIVIO_VERSION, QUIVIO_PORT, Volume quivio-data
- Frontend-Logo "W" -> "Q", Titel "Quivio", Footer
- Favicon "Q" (Georgia serif fuer klassischen Look)
- Logger-Name: watchstack -> quivio
- README, NOTICE, dist/README, data/README: Quivio
- CI-Workflow: testet quivio/ Pfade
- build-and-push.sh: lokaler Tag "quivio:VERSION"
- service-Feld in /api/health: quivio
- OpenAPI title: Quivio

Bugfix (gefunden beim Renaming):
- seed.py hatte versteckten "from app.database import DB_PATH" — gefixt

Verifiziert end-to-end:
- Python-Import OK
- Backend: service=quivio, version=0.5.1-beta, 8 unique items
- Docker-Build OK, Push in Gitea-Registry OK (neuer sha256-Digest)
- Container: Quivio 0.5.1-beta ready (logger), HTML ohne WatchStack-Rest
- OpenAPI title=Quivio
- 8 unique items nach cold start (Race-Fix haelt)
2026-07-22 00:42:09 +02:00

150 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Legt ein paar Demo-Datensätze an, falls die DB leer ist."""
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import logging
from datetime import date
from pathlib import Path
from filelock import FileLock
from sqlalchemy.orm import Session
from quivio import crud, models, schemas
log = logging.getLogger(__name__)
# File-Lock gegen Race-Conditions bei mehreren Workern (gunicorn).
# Pro Datenbank-Pfad ein Lock, damit parallele Worker nicht doppelt seeden.
def _lock_path() -> Path:
from quivio.database import DB_PATH
return DB_PATH.with_suffix(DB_PATH.suffix + ".seed.lock")
DEMO_BOOKS = [
{
"title": "Der Name des Windes",
"author": "Patrick Rothfuss",
"release_year": 2007,
"status": "done",
"rating": 9.0,
"total_pages": 662,
"pages_read": 662,
"genres": ["Fantasy", "Roman"],
"tags": ["Königsmörder-Chroniken"],
"description": "Kvothe erzählt sein Leben von der Kindheit bis zur Universität.",
"cover_url": "https://covers.openlibrary.org/b/isbn/9783608938284-L.jpg",
},
{
"title": "Project Hail Mary",
"author": "Andy Weir",
"release_year": 2021,
"status": "reading",
"rating": 8.5,
"total_pages": 476,
"pages_read": 120,
"genres": ["Science-Fiction", "Roman"],
"tags": ["Hard SF", "All-Age"],
"cover_url": "https://covers.openlibrary.org/b/isbn/9780593135204-L.jpg",
},
{
"title": "Atomic Habits",
"author": "James Clear",
"release_year": 2018,
"status": "plan",
"total_pages": 320,
"pages_read": 0,
"genres": ["Sachbuch", "Selbsthilfe"],
"tags": ["Produktivität"],
"cover_url": "https://covers.openlibrary.org/b/isbn/9780735211292-L.jpg",
},
{
"title": "Die Foundation",
"author": "Isaac Asimov",
"release_year": 1951,
"status": "dropped",
"rating": 6.0,
"total_pages": 244,
"pages_read": 80,
"genres": ["Science-Fiction", "Klassiker"],
"tags": ["Space Opera"],
"cover_url": "https://covers.openlibrary.org/b/isbn/9780553293357-L.jpg",
},
]
DEMO_SERIES = [
{
"title": "Breaking Bad",
"release_year": 2008,
"status": "done",
"rating": 9.5,
"total_seasons": 5,
"total_episodes": 62,
"episodes_watched": 62,
"network": "AMC",
"genres": ["Drama", "Thriller", "Crime"],
"tags": ["Anti-Held", "Must-Watch"],
"description": "Ein Chemielehrer steigt nach Krebsdiagnose in die Meth-Produktion ein.",
"cover_url": "https://m.media-amazon.com/images/M/MV5BYmQ4YWM2YWMtODNkNy00ZDNkLThiMDItZWE2MjAyMDUwYzhjL2ltYWdlL2ltYWdlXkEyXkFqcGdeQXVyMTMzNDExODE5._V1_.jpg",
},
{
"title": "Severance",
"release_year": 2022,
"status": "reading",
"rating": 8.7,
"total_seasons": 2,
"total_episodes": 19,
"episodes_watched": 9,
"season_watching": 1,
"network": "Apple TV+",
"genres": ["Sci-Fi", "Thriller", "Drama"],
"tags": ["Workplace", "Mind-Bender"],
"cover_url": "https://m.media-amazon.com/images/M/MV5BZjI0M2NlOTQtZmEzMy00MzMwLWEzYTktNmFhN2Q4NjIzNjRiXkEyXkFqcGdeQXVyMTEyMjM2NDc2._V1_.jpg",
},
{
"title": "One Piece",
"release_year": 1999,
"status": "plan",
"total_seasons": 21,
"total_episodes": 1100,
"episodes_watched": 0,
"network": "Toei Animation",
"genres": ["Anime", "Abenteuer", "Action"],
"tags": ["Long Runner"],
"cover_url": "https://m.media-amazon.com/images/M/MV5BODcwNWE3ZmMtYjIyZi00NzUxLTgwM2ItZGIwNTZjMjllNDdmXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_.jpg",
},
{
"title": "Dark",
"release_year": 2017,
"status": "hold",
"rating": 8.0,
"total_seasons": 3,
"total_episodes": 26,
"episodes_watched": 10,
"season_watching": 2,
"network": "Netflix",
"genres": ["Sci-Fi", "Mystery", "Thriller"],
"tags": ["Time-Travel", "DE"],
"cover_url": "https://m.media-amazon.com/images/M/MV5BYTRkNGE2MjItMjVkZi00MzVlLWE3NjgtMjI4N2QxY2Y3YjRiXkEyXkFqcGdeQXVyMTAzMDg4NzU0._V1_.jpg",
},
]
def seed_if_empty(db: Session) -> None:
"""Seedet genau einmal pro DB.
Mehrere gunicorn-Worker können gleichzeitig hochfahren und alle eine leere DB
sehen. Ein File-Lock serialisiert das Seeding prozessübergreifend.
"""
if db.query(models.Media).count() > 0:
return
lock = FileLock(str(_lock_path()), timeout=30)
with lock:
# Re-check unter Lock: ein anderer Worker hat womoeglich schon geseedet.
if db.query(models.Media).count() > 0:
return
log.info("Leere DB lege Demo-Daten an.")
for spec in DEMO_BOOKS:
crud.create_media(db, schemas.MediaCreate(kind="book", **spec))
for spec in DEMO_SERIES:
crud.create_media(db, schemas.MediaCreate(kind="series", **spec))