Initial commit: Filebot Media Browser
Vue 3 + FastAPI Webapp zur Anzeige von Filebot/n8n-Medienmetadaten aus PostgreSQL. Enthält Frontend, API, Nginx-Config, SQL-Migrationen und Docker-Compose-Setup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
# Projekt-Kontext für KI-Assistenten (Filebot Media Browser)
|
||||
|
||||
Diese Datei fasst zusammen, **was gebaut wurde** und wie das Projekt betrieben wird. Bei weiteren Änderungen zuerst hier und in der `README.md` nachschlagen.
|
||||
|
||||
---
|
||||
|
||||
## Zweck
|
||||
|
||||
Interne Web-App im Heimnetz zum Anzeigen und Verwalten von **Filebot/n8n-Medienmetadaten** aus PostgreSQL. Schwerpunkt: **Original- vs. neuem Dateinamen** nebeneinander (Rename-Kontrolle), plus technische Metadaten (Codec, Bitrate, Auflösung, …).
|
||||
|
||||
**Produktiv nur auf dem Server** unter `/opt/nginx_filebot` – nicht lokal auf dem Mac entwickeln/ausführen.
|
||||
|
||||
---
|
||||
|
||||
## Infrastruktur
|
||||
|
||||
| Komponente | Details |
|
||||
|------------|---------|
|
||||
| Server-Pfad | `/opt/nginx_filebot` |
|
||||
| Docker Compose | Projektname `nginx_filebot` |
|
||||
| Web | Nginx, Port **8080** → Container 80 |
|
||||
| API | FastAPI (Python 3.12), intern `api:8000` |
|
||||
| PostgreSQL | Host typisch `192.168.30.186` |
|
||||
| Datenbank | `n8n_filebot` (Name in config) |
|
||||
| Schema | **`n8n`** (nicht `public`!) |
|
||||
| Tabelle | **`movie_files`** (nicht `n8n_filebot`!) |
|
||||
| Vollqualifizierter Name | `"n8n"."movie_files"` |
|
||||
|
||||
Config: `config/config.yaml` (nur auf Server, nicht committen). Beispiel: `config/config.example.yaml`.
|
||||
|
||||
**Wichtig:** Feld `schema` in YAML funktioniert, intern heißt es `db_schema` (Pydantic-Konflikt mit `BaseModel.schema`).
|
||||
|
||||
---
|
||||
|
||||
## Tech-Stack
|
||||
|
||||
- **Frontend:** Vue 3, TypeScript, Vite, TanStack Table
|
||||
- **Backend:** FastAPI, asyncpg
|
||||
- **Webserver:** Nginx (Multi-Stage-Build: Node baut Vue, Nginx liefert aus)
|
||||
- **DB:** PostgreSQL
|
||||
|
||||
---
|
||||
|
||||
## Datenbank-Spalten (relevant)
|
||||
|
||||
Standard-Spalten aus n8n/Filebot (siehe `api/main.py` → `COLUMNS`), u. a.:
|
||||
|
||||
- `id`, `file_name_original`, `file_name_new`
|
||||
- `movie_rating`, `movie_votes`
|
||||
- Video/Audio: `standard_video_format`, `video_codec_library`, `audio_codec`, `container_format`, Bitraten, Auflösung, …
|
||||
- `created_at`
|
||||
|
||||
**Zusätzlich per Migration:**
|
||||
|
||||
| Spalte | Typ | Bedeutung |
|
||||
|--------|-----|-----------|
|
||||
| `seen_at` | `TIMESTAMPTZ NULL` | `NULL` = ungesehen; gesetzt = in UI als gesehen markiert |
|
||||
| `cover_url` | `TEXT NULL` | Poster-URL (z. B. TVMaze), erste Tabellenspalte |
|
||||
|
||||
SQL-Dateien: `sql/001_add_seen_at.sql`, `sql/002_add_cover_url.sql`
|
||||
|
||||
**n8n:** Bei INSERT/UPDATE `seen_at` und `cover_url` nicht ungewollt überschreiben.
|
||||
|
||||
---
|
||||
|
||||
## UI-Funktionen (Stand Projektabschluss)
|
||||
|
||||
### Layout
|
||||
|
||||
- **Desktop:** Tabelle mit vielen Spalten; **erste Spalte Cover** (ca. 76×114 px), dann Dateinamen-Paar
|
||||
- **Mobile (≤900px):** Karten mit Cover links
|
||||
- **Helles Dark-Theme** (`frontend/src/styles.css`, CSS-Variablen)
|
||||
|
||||
### Dateinamen
|
||||
|
||||
- Immer **Original** und **Neu** sichtbar (`NamePair.vue`)
|
||||
- Kein „Rename prüfen“-Badge mehr (Heuristik entfernt)
|
||||
|
||||
### Filter (`FilterBar.vue`)
|
||||
|
||||
- Textsuche in Original + Neu
|
||||
- **Buttons** (keine Dropdowns): Format, Codec, Container
|
||||
- **Datum/Uhrzeit Von–Bis** mit Kalender-Popup + HH:MM-Dropdowns (`DateTimeRangeFilter.vue`)
|
||||
- **Gesehen:** „Nur ungesehen“, „Alle als gesehen“, Zähler „X neu“
|
||||
- Aktualisieren / Zurücksetzen
|
||||
|
||||
### Gesehen-Status
|
||||
|
||||
- Ungesehene Zeilen: blauer linker Rand + Hintergrund (`row-unseen` / `card-unseen`)
|
||||
- **Tippen auf Zeile** (nicht Scroll): Toggle gesehen/ungesehen via `PATCH /api/records/{id}/seen`
|
||||
- Mülleimer löscht Eintrag (kein Toggle)
|
||||
|
||||
### Tabelle
|
||||
|
||||
- Sortierung Standard: `created_at` absteigend (neueste oben)
|
||||
- Schnellfilter in geladenen Daten
|
||||
- **Löschen:** roter Mülleimer pro Zeile → `DELETE /api/records/{id}`
|
||||
|
||||
### Cover
|
||||
|
||||
- `CoverImage.vue`: lazy load, Platzhalter bei Fehler, URL-Bereinigung (extra `"` entfernen)
|
||||
|
||||
---
|
||||
|
||||
## API-Endpunkte
|
||||
|
||||
| Methode | Pfad | Beschreibung |
|
||||
|---------|------|--------------|
|
||||
| GET | `/api/health` | DB-Ping |
|
||||
| GET | `/api/status` | Diagnose (Config, Tabellenliste bei Fehler) |
|
||||
| GET | `/api/columns` | Spaltenliste |
|
||||
| GET | `/api/records` | Daten; Query: `search`, `format`, `codec`, `container`, `created_from`, `created_to`, `unseen_only` |
|
||||
| GET | `/api/filters` | Distinct-Werte für Filter-Buttons |
|
||||
| PATCH | `/api/records/{id}/seen` | Body: `{ "seen": true \| false }` |
|
||||
| POST | `/api/records/mark-all-seen` | Alle gefilterten als gesehen |
|
||||
| DELETE | `/api/records/{id}` | Zeile löschen |
|
||||
|
||||
Nginx proxied `/api/` → `http://api:8000/api/`.
|
||||
|
||||
---
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```text
|
||||
/opt/nginx_filebot/
|
||||
├── docker-compose.yml # absolute Pfade für Server
|
||||
├── config/
|
||||
│ ├── config.example.yaml
|
||||
│ └── config.yaml # nur Server
|
||||
├── api/
|
||||
│ ├── main.py
|
||||
│ ├── config.py
|
||||
│ ├── Dockerfile
|
||||
│ └── scripts/list-tables.py
|
||||
├── frontend/
|
||||
│ └── src/
|
||||
│ ├── App.vue
|
||||
│ ├── api.ts
|
||||
│ ├── components/ # DataTable, FilterBar, CoverImage, …
|
||||
│ ├── composables/ # (useSeenObserver entfernt)
|
||||
│ └── utils/
|
||||
├── nginx/
|
||||
│ ├── Dockerfile # Multi-Stage Frontend-Build
|
||||
│ └── nginx.conf
|
||||
├── sql/ # DB-Migrationen
|
||||
├── PROMPT.md # diese Datei
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment (Kurz)
|
||||
|
||||
```bash
|
||||
cd /opt/nginx_filebot
|
||||
docker compose up -d --build
|
||||
# Browser: http://<server-ip>:8080
|
||||
```
|
||||
|
||||
Nach Frontend-Änderungen: `docker compose up -d --build web`
|
||||
Nach API-Änderungen: `docker compose up -d --build api`
|
||||
Oft: komplett `--build`
|
||||
|
||||
---
|
||||
|
||||
## Typische Fehler (bereits aufgetreten)
|
||||
|
||||
1. **`relation "n8n_filebot" does not exist`** → Tabelle heißt `movie_files`, DB `n8n_filebot`
|
||||
2. **`schema: n8n` ignoriert** → `db_schema` / API-Fix mit `validation_alias`
|
||||
3. **Leere DB-Liste** → falsche Datenbank oder leere Tabelle
|
||||
4. **API 500 ohne `seen_at`/`cover_url`** → SQL-Migration ausführen
|
||||
5. **Design ändert sich nicht** → `web` neu bauen + Browser Hard-Reload
|
||||
|
||||
Diagnose:
|
||||
|
||||
```bash
|
||||
docker compose logs api --tail 50
|
||||
curl -s http://localhost:8080/api/status
|
||||
docker compose exec api python /app/scripts/list-tables.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Konventionen für weitere Entwicklung
|
||||
|
||||
- Antworten an Nutzer oft **auf Deutsch**
|
||||
- Keine Commits unless asked
|
||||
- `config.yaml` nie ins Git
|
||||
- Server-only Deployment kommunizieren
|
||||
- Nach Änderungen: welche Dateien hochladen + `docker compose up -d --build`
|
||||
- Minimale Diffs, bestehenden Stil beibehalten (Vue 3 Composition API, FastAPI async)
|
||||
|
||||
---
|
||||
|
||||
## Nutzer-Präferenzen (aus Session)
|
||||
|
||||
- Rename-Kontrolle: `file_name_original` + `file_name_new` immer sichtbar
|
||||
- Filter als Buttons, nebeneinander (mobil gestapelt)
|
||||
- Gesehen per **Tap**, nicht Scroll
|
||||
- Cover in erster Spalte, etwas höhere Zeilen
|
||||
- Etwas **helleres** UI-Theme
|
||||
Reference in New Issue
Block a user