"""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 app 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 app.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))