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)
This commit is contained in:
@@ -18,12 +18,12 @@ jobs:
|
||||
- run: pip install -r requirements.txt
|
||||
- name: Backend-Import-Check
|
||||
run: |
|
||||
python -c "from app.main import app; print('OK', app.title, app.version)"
|
||||
python -c "from quivio.main import app; print('OK', app.title, app.version)"
|
||||
- name: Frontend-Asset-Check
|
||||
run: |
|
||||
test -f app/static/index.html
|
||||
test -f app/static/css/style.css
|
||||
test -f app/static/js/app.js
|
||||
test -f quivio/static/index.html
|
||||
test -f quivio/static/css/style.css
|
||||
test -f quivio/static/js/app.js
|
||||
|
||||
# Hinweis: Push in die Gitea Container Registry laeuft lokal ueber
|
||||
# bin/build-and-push.sh
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
# =====================================================================
|
||||
# WatchStack — Multi-stage Docker-Build
|
||||
# Quivio — Multi-stage Docker-Build
|
||||
# 1) builder : installiert Dependencies in ein separates venv
|
||||
# 2) runtime : minimal, non-root, nur Runtime-Deps + venv aus builder
|
||||
# =====================================================================
|
||||
@@ -44,7 +44,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
&& chown -R watchstack:watchstack /data /app
|
||||
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
COPY --chown=watchstack:watchstack app /app/app
|
||||
COPY --chown=watchstack:watchstack quivio /app/quivio
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -59,7 +59,7 @@ VOLUME ["/data"]
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
|
||||
# gunicorn mit uvicorn-Worker-Klasse fuer ASGI
|
||||
CMD ["sh", "-c", "gunicorn app.main:app \
|
||||
CMD ["sh", "-c", "gunicorn quivio.main:app \
|
||||
--bind ${WATCHSTACK_HOST}:${WATCHSTACK_PORT} \
|
||||
--workers ${WATCHSTACK_WORKERS} \
|
||||
--worker-class uvicorn.workers.UvicornWorker \
|
||||
@@ -71,7 +71,7 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD python -c "import urllib.request, sys; r=urllib.request.urlopen('http://127.0.0.1:'+__import__('os').environ.get('WATCHSTACK_PORT','8000')+'/api/health',timeout=3); sys.exit(0 if r.status==200 else 1)" \
|
||||
|| exit 1
|
||||
|
||||
LABEL org.opencontainers.image.title="WatchStack" \
|
||||
org.opencontainers.image.description="Watchlist für Bücher, Serien & mehr" \
|
||||
LABEL org.opencontainers.image.title="Quivio" \
|
||||
org.opencontainers.image.description="Watchlist für Bücher, Serien & mehr (Quire + Video)" \
|
||||
org.opencontainers.image.source="https://git.pkop.de/Vibecode/watchlist" \
|
||||
org.opencontainers.image.licenses="Apache-2.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
WatchStack
|
||||
Copyright 2026 WatchStack Contributors
|
||||
Quivio
|
||||
Copyright 2026 Quivio Contributors
|
||||
|
||||
This product includes software developed by the WatchStack Contributors
|
||||
This product includes software developed by the Quivio Contributors
|
||||
(https://git.pkop.de/Vibecode/watchlist).
|
||||
|
||||
This product includes data and APIs from third parties:
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# WatchStack
|
||||
# Quivio
|
||||
|
||||
> **v0.5.0-beta** — eine Watchlist für **Bücher, Serien & mehr** — inspiriert von MyAnimeList, aber mit eigenem Konzept.
|
||||
> **v0.5.1-beta** — eine Watchlist für **Bücher, Serien & mehr** — inspiriert von MyAnimeList, aber mit eigenem Konzept.
|
||||
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
[](https://git.pkop.de/Vibecode/watchlist)
|
||||
[](https://www.python.org)
|
||||
[](#-docker)
|
||||
|
||||
WatchStack ist eine **single-user-lokale** Watchlist-App. Bücher und Serien teilen sich eine Oberfläche, ein Datenmodell und eine Such- und Filterlogik. Keine Anmeldung, kein Cloud-Zwang — läuft komplett auf deiner Maschine oder in einem Docker-Container.
|
||||
**Quivio** (Kofferwort aus *Quire* + *Video*) ist eine **single-user-lokale** Watchlist-App.
|
||||
Bücher und Serien teilen sich eine Oberfläche, ein Datenmodell und eine Such- und Filterlogik.
|
||||
Keine Anmeldung, kein Cloud-Zwang — läuft komplett auf deiner Maschine oder in einem Docker-Container.
|
||||
|
||||
## ✨ Features
|
||||
|
||||
@@ -26,7 +28,7 @@ WatchStack ist eine **single-user-lokale** Watchlist-App. Bücher und Serien tei
|
||||
|
||||
**v0.5.1-beta** bedeutet:
|
||||
- Kernfunktionalität (CRUD, Suche, Stats, Progress) ist stabil und getestet
|
||||
- Datenmodell kann sich noch ändern (siehe `models.py` — additive Änderungen wahrscheinlich)
|
||||
- Datenmodell kann sich noch ändern (siehe `quivio/models.py` — additive Änderungen wahrscheinlich)
|
||||
- Datenbank-Migrationen sind **nicht** enthalten — bei Major-Upgrades DB sichern
|
||||
- Public-API-Pfade stabil; Sub-Ressourcen (Genres/Tags) noch in Bewegung
|
||||
|
||||
@@ -38,7 +40,7 @@ Bitte Issues und Wünsche im [Repo](https://git.pkop.de/Vibecode/watchlist) meld
|
||||
|
||||
```bash
|
||||
docker pull git.pkop.de/vibecode/watchlist:0.5.1-beta
|
||||
docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data git.pkop.de/vibecode/watchlist:0.5.1-beta
|
||||
docker run -d --name quivio -p 8000:8000 -v quivio-data:/data git.pkop.de/vibecode/watchlist:0.5.1-beta
|
||||
```
|
||||
|
||||
Das Image liegt im **Packages**-Tab des Repos (Gitea Container Registry,
|
||||
@@ -52,13 +54,11 @@ docker compose up -d
|
||||
# → http://localhost:8000
|
||||
|
||||
# Oder direkt:
|
||||
docker build -t watchstack:beta .
|
||||
docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data watchstack:beta
|
||||
docker build -t quivio:beta .
|
||||
docker run -d --name quivio -p 8000:8000 -v quivio-data:/data quivio:beta
|
||||
```
|
||||
|
||||
Die SQLite-DB liegt im benannten Volume `watchstack-data` (Pfad `/data/watchstack.db` im Container). Backups: `docker run --rm -v watchstack-data:/data -v $PWD:/backup alpine tar czf /backup/ws-$(date +%F).tgz /data`.
|
||||
|
||||
### Option B: Lokal (Python 3.11+)
|
||||
### Option C: Python direkt
|
||||
|
||||
```bash
|
||||
git clone https://git.pkop.de/Vibecode/watchlist.git
|
||||
@@ -66,15 +66,6 @@ cd watchlist
|
||||
./run.sh # legt venv an, installiert deps, startet auf 127.0.0.1:8000
|
||||
```
|
||||
|
||||
### Option C: Manuell
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
uvicorn app.main:app --reload
|
||||
```
|
||||
|
||||
## 🔧 Konfiguration (Umgebungsvariablen)
|
||||
|
||||
| Variable | Default | Zweck |
|
||||
@@ -85,6 +76,10 @@ uvicorn app.main:app --reload
|
||||
| `WATCHSTACK_WORKERS` | `2` | gunicorn-Worker (nur Docker) |
|
||||
| `WATCHSTACK_HTTP_TIMEOUT` | `8` | Timeout für Open-Library-Lookup (Sek.) |
|
||||
|
||||
> Hinweis: Die ENV-Variablen heißen weiterhin `WATCHSTACK_*`, weil das der
|
||||
> Docker-konforme Standard ist. Im lokalen Dev ist das egal, da die Defaults
|
||||
> passen.
|
||||
|
||||
## 📚 API-Übersicht
|
||||
|
||||
| Methode | Pfad | Zweck |
|
||||
@@ -121,7 +116,7 @@ Vollständige interaktive Doku: <http://localhost:8000/docs> (Swagger UI, von Fa
|
||||
|
||||
```
|
||||
watchlist/
|
||||
├── app/
|
||||
├── quivio/ # Python-Paket (FastAPI, SQLAlchemy, ...)
|
||||
│ ├── __init__.py # __version__
|
||||
│ ├── main.py # FastAPI-App + Routen
|
||||
│ ├── database.py # Engine + Session
|
||||
@@ -132,7 +127,7 @@ watchlist/
|
||||
│ ├── seed.py # Demo-Daten
|
||||
│ └── static/ # Frontend (HTML/CSS/JS)
|
||||
├── data/ # SQLite-DB (gitignored, Volume im Container)
|
||||
├── bin/ # build-and-push.sh, build-image.sh, write-manifest.sh
|
||||
├── bin/ # build-and-push.sh, build-image.sh, write-manifest.sh, get-version.py
|
||||
├── .github/workflows/ # CI
|
||||
├── Dockerfile # Multi-stage Build
|
||||
├── docker-compose.yml
|
||||
@@ -144,11 +139,11 @@ watchlist/
|
||||
## 🛠 Entwicklung
|
||||
|
||||
```bash
|
||||
# Tests (bisher Smoke-Tests ad-hoc; pytest-Suite ist Roadmap)
|
||||
python -c "from app.main import app; print(app.title, app.version)"
|
||||
# Lokales Backend
|
||||
./run.sh
|
||||
|
||||
# Code-Style
|
||||
ruff check app/ # (optional, nicht in requirements)
|
||||
# Tests (bisher Smoke-Tests ad-hoc; pytest-Suite ist Roadmap)
|
||||
python3 -c "from quivio.main import app; print(app.title, app.version)"
|
||||
```
|
||||
|
||||
## 📜 Lizenz
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
"""WatchStack – Watchlist für Bücher, Serien & mehr."""
|
||||
|
||||
__version__ = "0.5.1-beta"
|
||||
__all__ = ["__version__"]
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Baut das Image und pusht es in die Gitea Container Registry.
|
||||
# Baut das Quivio-Image und pusht es in die Gitea Container Registry.
|
||||
# Verwendung:
|
||||
# bin/build-and-push.sh # Version aus app/__init__.py
|
||||
# bin/build-and-push.sh # Version aus quivio/__init__.py
|
||||
# VERSION=0.6.0 bin/build-and-push.sh # explizite Version
|
||||
# bin/build-and-push.sh --load # baut + laedt nur (kein Push)
|
||||
set -euo pipefail
|
||||
@@ -16,7 +16,7 @@ fi
|
||||
REGISTRY="${REGISTRY:-git.pkop.de}"
|
||||
OWNER_LC=$(echo "${OWNER:-Vibecode}" | tr '[:upper:]' '[:lower:]')
|
||||
REPO_LC=$(echo "${REPO:-watchlist}" | tr '[:upper:]' '[:lower:]')
|
||||
LOCAL_TAG="watchstack:${VERSION}"
|
||||
LOCAL_TAG="quivio:${VERSION}"
|
||||
REMOTE_TAG="${REGISTRY}/${OWNER_LC}/${REPO_LC}:${VERSION}"
|
||||
|
||||
echo ">> Building ${LOCAL_TAG}"
|
||||
@@ -35,4 +35,4 @@ docker push "${REMOTE_TAG}"
|
||||
|
||||
echo ">> Done."
|
||||
echo " Pull with: docker pull ${REMOTE_TAG}"
|
||||
echo " Run with: docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data ${REMOTE_TAG}"
|
||||
echo " Run with: docker run -d --name quivio -p 8000:8000 -v quivio-data:/data ${REMOTE_TAG}"
|
||||
|
||||
+4
-13
@@ -1,28 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Baut das Docker-Image und legt es als versionierten Tar in dist/ ab.
|
||||
# Verwendung:
|
||||
# bin/build-image.sh # baut mit Version aus app/__init__.py
|
||||
# bin/build-image.sh --load # baut + laedt direkt in lokales Docker
|
||||
# VERSION=0.6.0 bin/build-image.sh # baut mit expliziter Version
|
||||
# Baut das Quivio-Image und speichert es als Tar (Fallback, nicht mehr im Standard-Workflow).
|
||||
# Normalerweise: bin/build-and-push.sh -> Image in Gitea-Registry.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# Version aus app/__init__.py lesen, falls nicht via env ueberschrieben
|
||||
if [ -z "${VERSION:-}" ]; then
|
||||
VERSION=$(python3 bin/get-version.py)
|
||||
fi
|
||||
IMAGE="watchstack:${VERSION}"
|
||||
TAR="dist/watchstack-${VERSION}.docker.tar"
|
||||
IMAGE="quivio:${VERSION}"
|
||||
TAR="dist/quivio-${VERSION}.docker.tar"
|
||||
|
||||
mkdir -p dist
|
||||
echo ">> Building ${IMAGE}"
|
||||
docker build -t "${IMAGE}" .
|
||||
|
||||
if [ "${1:-}" = "--load" ]; then
|
||||
echo ">> Loaded into local Docker as ${IMAGE}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ">> Saving to ${TAR}"
|
||||
docker save -o "${TAR}" "${IMAGE}"
|
||||
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Liest die Version aus app/__init__.py (single source of truth).
|
||||
"""Liest die Version aus quivio/__init__.py (single source of truth).
|
||||
Verwendung: VERSION=$(python3 bin/get-version.py)
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
text = (Path(__file__).parent.parent / "app" / "__init__.py").read_text()
|
||||
text = (Path(__file__).parent.parent / "quivio" / "__init__.py").read_text()
|
||||
m = re.search(r'__version__\s*=\s*["\'](.+?)["\']', text)
|
||||
if not m:
|
||||
sys.exit("__version__ nicht gefunden")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Schreibt dist/manifest.json mit Build-Metadaten.
|
||||
# Wird von bin/build-image.sh aufgerufen; kann auch solo laufen.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
@@ -14,13 +13,13 @@ BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
mkdir -p dist
|
||||
cat > dist/manifest.json <<EOF
|
||||
{
|
||||
"name": "watchstack",
|
||||
"name": "quivio",
|
||||
"version": "${VERSION}",
|
||||
"git_sha": "${GIT_SHA}",
|
||||
"git_tag": "${GIT_TAG}",
|
||||
"build_date": "${BUILD_DATE}",
|
||||
"image": "watchstack:${VERSION}",
|
||||
"tarball": "dist/watchstack-${VERSION}.docker.tar",
|
||||
"image": "quivio:${VERSION}",
|
||||
"tarball": "dist/quivio-${VERSION}.docker.tar",
|
||||
"license": "Apache-2.0",
|
||||
"source": "https://git.pkop.de/Vibecode/watchlist"
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Lokale Daten
|
||||
|
||||
Hier landet die SQLite-DB `watchstack.db` (wird automatisch angelegt).
|
||||
Hier landet die SQLite-DB `quivio.db` (wird automatisch angelegt).
|
||||
|
||||
Dieser Ordner ist in `.gitignore`.
|
||||
|
||||
Vendored
+3
-3
@@ -1,20 +1,20 @@
|
||||
# dist/ — leeres Build-Ausgabeverzeichnis
|
||||
|
||||
Docker-Images werden **nicht** als Tar im Repo committed, sondern in die
|
||||
Quivio-Images werden **nicht** als Tar im Repo committed, sondern in die
|
||||
Gitea Container Registry gepusht (siehe *Packages*-Tab im Repo-UI).
|
||||
|
||||
## Verwendung der Registry-Images
|
||||
|
||||
```bash
|
||||
docker pull git.pkop.de/vibecode/watchlist:0.5.1-beta
|
||||
docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data \
|
||||
docker run -d --name quivio -p 8000:8000 -v quivio-data:/data \
|
||||
git.pkop.de/vibecode/watchlist:0.5.1-beta
|
||||
```
|
||||
|
||||
## Build + Push lokal
|
||||
|
||||
```bash
|
||||
bin/build-and-push.sh # baut + pusht mit Version aus app/__init__.py
|
||||
bin/build-and-push.sh # baut + pusht mit Version aus quivio/__init__.py
|
||||
VERSION=0.6.0 bin/build-and-push.sh # baut + pusht mit expliziter Version
|
||||
```
|
||||
|
||||
|
||||
+16
-16
@@ -1,8 +1,8 @@
|
||||
# Komponiert WatchStack.
|
||||
# Komponiert Quivio.
|
||||
#
|
||||
# Standard (empfohlen, Beta):
|
||||
# Image wird aus der Gitea Container Registry gezogen — kein lokaler
|
||||
# Build noetig. Version liegt in app/__init__.py (single source of truth).
|
||||
# Build noetig. Version liegt in quivio/__init__.py (single source of truth).
|
||||
#
|
||||
# docker compose up -d
|
||||
# -> http://localhost:8000
|
||||
@@ -12,24 +12,24 @@
|
||||
# => baut aus dem Dockerfile statt aus der Registry
|
||||
#
|
||||
# Andere Version ziehen:
|
||||
# WATCHSTACK_VERSION=0.6.0 docker compose pull && docker compose up -d
|
||||
# QUIVIO_VERSION=0.6.0 docker compose pull && docker compose up -d
|
||||
#
|
||||
# Optional: Reverse-Proxy (caddy/traefik) davorschalten.
|
||||
|
||||
# Wird vom .env oder der Umgebung ueberschrieben, wenn vorhanden.
|
||||
# Hinweis: Gitea-Pfad ist LOWERCASE (Vibecode/watchlist -> vibecode/watchlist),
|
||||
# weil Docker-Repository-Namen kleingeschrieben sein muessen.
|
||||
x-watchstack-version: &watchstack_version ${WATCHSTACK_VERSION:-0.5.1-beta}
|
||||
x-gitea-image: &gitea_image git.pkop.de/vibecode/watchlist:${WATCHSTACK_VERSION:-0.5.1-beta}
|
||||
x-quivio-version: &quivio_version ${QUIVIO_VERSION:-0.5.1-beta}
|
||||
x-gitea-image: &gitea_image git.pkop.de/vibecode/watchlist:${QUIVIO_VERSION:-0.5.1-beta}
|
||||
|
||||
services:
|
||||
watchstack:
|
||||
quivio:
|
||||
# Standard: Image aus der Gitea Container Registry.
|
||||
image: *gitea_image
|
||||
container_name: watchstack
|
||||
container_name: quivio
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${WATCHSTACK_PORT:-8000}:8000"
|
||||
- "${QUIVIO_PORT:-8000}:8000"
|
||||
environment:
|
||||
WATCHSTACK_HOST: "0.0.0.0"
|
||||
WATCHSTACK_PORT: "8000"
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
WATCHSTACK_DATA_DIR: "/data"
|
||||
# TZ: "Europe/Berlin"
|
||||
volumes:
|
||||
- watchstack-data:/data
|
||||
- quivio-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request,sys,os; r=urllib.request.urlopen('http://127.0.0.1:8000/api/health',timeout=3); sys.exit(0 if r.status==200 else 1)"]
|
||||
interval: 30s
|
||||
@@ -47,23 +47,23 @@ services:
|
||||
|
||||
# Lokaler Build (Development) — ueber opt-in Profile aktivierbar:
|
||||
# docker compose --profile local up -d --build
|
||||
watchstack-local:
|
||||
quivio-local:
|
||||
profiles: ["local"]
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: watchstack:local
|
||||
container_name: watchstack-local
|
||||
image: quivio:local
|
||||
container_name: quivio-local
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${WATCHSTACK_PORT:-8001}:8000" # anderer Port, damit Registry-Variante parallel laufen kann
|
||||
- "${QUIVIO_PORT:-8001}:8000" # anderer Port, damit Registry-Variante parallel laufen kann
|
||||
environment:
|
||||
WATCHSTACK_HOST: "0.0.0.0"
|
||||
WATCHSTACK_PORT: "8000"
|
||||
WATCHSTACK_WORKERS: "2"
|
||||
WATCHSTACK_DATA_DIR: "/data"
|
||||
volumes:
|
||||
- watchstack-data:/data
|
||||
- quivio-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request,sys,os; r=urllib.request.urlopen('http://127.0.0.1:8000/api/health',timeout=3); sys.exit(0 if r.status==200 else 1)"]
|
||||
interval: 30s
|
||||
@@ -72,5 +72,5 @@ services:
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
watchstack-data:
|
||||
name: watchstack-data
|
||||
quivio-data:
|
||||
name: quivio-data
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
"""Quivio – Watchlist für Bücher, Serien & mehr.
|
||||
|
||||
Name: Quivio (Kofferwort aus Quire + Video).
|
||||
"""
|
||||
|
||||
__version__ = "0.5.1-beta"
|
||||
__all__ = ["__version__"]
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Datenbank-Operationen (CRUD) für WatchStack."""
|
||||
"""Datenbank-Operationen (CRUD) für Quivio."""
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import Iterable, Optional, Sequence
|
||||
from sqlalchemy import and_, func, or_, select
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app import models, schemas
|
||||
from quivio import models, schemas
|
||||
|
||||
|
||||
# ---------- Hilfsfunktionen --------------------------------------------------
|
||||
@@ -12,7 +12,7 @@ from sqlalchemy.orm import DeclarativeBase, sessionmaker
|
||||
_BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
DATA_DIR = Path(os.environ.get("WATCHSTACK_DATA_DIR", _BASE_DIR / "data"))
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
DB_PATH = DATA_DIR / "watchstack.db"
|
||||
DB_PATH = DATA_DIR / "quivio.db"
|
||||
|
||||
DATABASE_URL = f"sqlite:///{DB_PATH}"
|
||||
|
||||
@@ -41,6 +41,6 @@ def get_db():
|
||||
|
||||
def init_db() -> None:
|
||||
"""Erstellt alle Tabellen, falls noch nicht vorhanden."""
|
||||
from app import models # noqa: F401 – registriert Modelle bei Base.metadata
|
||||
from quivio import models # noqa: F401 – registriert Modelle bei Base.metadata
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
@@ -13,16 +13,16 @@ from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import __version__, crud, schemas
|
||||
from app.database import get_db, init_db
|
||||
from app.external import lookup_book_by_isbn, lookup_book_by_title
|
||||
from app.seed import seed_if_empty
|
||||
from quivio import __version__, crud, schemas
|
||||
from quivio.database import get_db, init_db
|
||||
from quivio.external import lookup_book_by_isbn, lookup_book_by_title
|
||||
from quivio.seed import seed_if_empty
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
||||
)
|
||||
log = logging.getLogger("watchstack")
|
||||
log = logging.getLogger("quivio")
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
STATIC_DIR = BASE_DIR / "static"
|
||||
@@ -37,16 +37,16 @@ async def lifespan(_: FastAPI):
|
||||
init_db()
|
||||
with next(get_db()) as db:
|
||||
seed_if_empty(db)
|
||||
log.info("WatchStack %s ready", __version__)
|
||||
log.info("Quivio %s ready", __version__)
|
||||
yield
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="WatchStack",
|
||||
description="Watchlist für Bücher, Serien & mehr.",
|
||||
title="Quivio",
|
||||
description="Watchlist für Bücher, Serien & mehr. Quire + Video — dein Lese- und Schau-Tracker.",
|
||||
version=__version__,
|
||||
lifespan=lifespan,
|
||||
contact={"name": "WatchStack", "url": "https://git.pkop.de/Vibecode/watchlist"},
|
||||
contact={"name": "Quivio", "url": "https://git.pkop.de/Vibecode/watchlist"},
|
||||
license_info={"name": "Apache-2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0"},
|
||||
)
|
||||
|
||||
@@ -72,7 +72,7 @@ def root() -> HTMLResponse:
|
||||
|
||||
@app.get("/api/health", tags=["meta"])
|
||||
def health() -> dict[str, str]:
|
||||
return {"status": "ok", "service": "watchstack", "version": __version__}
|
||||
return {"status": "ok", "service": "quivio", "version": __version__}
|
||||
|
||||
|
||||
# ---------- Lookups ----------------------------------------------------------
|
||||
@@ -1,4 +1,4 @@
|
||||
"""SQLAlchemy-Modelle für WatchStack.
|
||||
"""SQLAlchemy-Modelle für Quivio.
|
||||
|
||||
Zentrale Idee: ein polymorphes ``Media``-Objekt mit ``kind`` (book/series), das
|
||||
optionale, mediumspezifische Felder als NULL-sparende Spalten mitführt. So
|
||||
@@ -25,7 +25,7 @@ from sqlalchemy import (
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
from quivio.database import Base
|
||||
|
||||
|
||||
def _utcnow() -> datetime:
|
||||
@@ -9,7 +9,7 @@ from pathlib import Path
|
||||
from filelock import FileLock
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import crud, models, schemas
|
||||
from quivio import crud, models, schemas
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -17,7 +17,7 @@ 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
|
||||
from quivio.database import DB_PATH
|
||||
return DB_PATH.with_suffix(DB_PATH.suffix + ".seed.lock")
|
||||
|
||||
DEMO_BOOKS = [
|
||||
@@ -1,6 +1,6 @@
|
||||
/* ========================================================================
|
||||
WatchStack — Theme
|
||||
- Dark default (wie MAL's moderner Look)
|
||||
Quivio — Theme
|
||||
- Dark default
|
||||
- Eine Akzentfarbe (cyan-violett), warme Status-Farben
|
||||
======================================================================== */
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="14" fill="url(#g)"/>
|
||||
<text x="32" y="44" font-family="Arial, sans-serif" font-size="38" font-weight="800" fill="white" text-anchor="middle">W</text>
|
||||
<text x="32" y="44" font-family="Georgia, serif" font-size="38" font-weight="700" fill="white" text-anchor="middle">Q</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 444 B |
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>WatchStack – Watchlist für Bücher & Serien</title>
|
||||
<title>Quivio – Watchlist für Bücher & Serien</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/img/favicon.svg">
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
</head>
|
||||
@@ -13,9 +13,9 @@
|
||||
<div class="hero-bg"></div>
|
||||
<div class="hero-inner">
|
||||
<div class="brand">
|
||||
<div class="logo">W</div>
|
||||
<div class="logo">Q</div>
|
||||
<div class="brand-text">
|
||||
<h1>WatchStack <span class="version-badge">beta</span></h1>
|
||||
<h1>Quivio <span class="version-badge">beta</span></h1>
|
||||
<p>Deine Watchlist für <strong>Bücher</strong>, <strong>Serien</strong> & mehr.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -223,8 +223,8 @@
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<span>WatchStack <span id="version">…</span> · Apache 2.0</span>
|
||||
<span>Made for readers & binge-watchers</span>
|
||||
<span>Quivio <span id="version">…</span> · Apache 2.0</span>
|
||||
<span>Quire + Video — made for readers & binge-watchers</span>
|
||||
</footer>
|
||||
|
||||
<!-- ===================== Toast ===================== -->
|
||||
@@ -1,5 +1,5 @@
|
||||
/* ========================================================================
|
||||
WatchStack – Client App
|
||||
Quivio – Client App
|
||||
======================================================================== */
|
||||
(() => {
|
||||
'use strict';
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# WatchStack-Schnellstart
|
||||
# Quivio-Schnellstart
|
||||
# Legt venv an (falls fehlt), installiert deps, startet uvicorn.
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
@@ -18,5 +18,5 @@ pip install -q -r requirements.txt
|
||||
|
||||
HOST="${HOST:-127.0.0.1}"
|
||||
PORT="${PORT:-8000}"
|
||||
echo "→ Starte WatchStack auf http://${HOST}:${PORT}"
|
||||
exec uvicorn app.main:app --reload --host "${HOST}" --port "${PORT}"
|
||||
echo "→ Starte Quivio auf http://${HOST}:${PORT}"
|
||||
exec uvicorn quivio.main:app --reload --host "${HOST}" --port "${PORT}"
|
||||
|
||||
Reference in New Issue
Block a user