0.14.0-4 Merger
Deploy Docs to GitHub Pages / Build Documentation (push) Has been cancelled
Deploy Docs to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled

This commit is contained in:
2026-04-21 14:27:07 +00:00
parent caf6a638f7
commit c27a81cdb1
127 changed files with 10643 additions and 335 deletions
+75 -67
View File
@@ -1,27 +1,31 @@
# History API
Endpunkte für Job-Historie, Orphan-Import und Löschoperationen.
Endpunkte für Job-Historie, Metadaten-Nachpflege, Orphan-Import und Löschoperationen.
---
## GET /api/history
Liefert Jobs (optionale Filter).
Liefert Jobs mit optionalen Filtern.
**Query-Parameter:**
| Parameter | Typ | Beschreibung |
|----------|-----|-------------|
| `status` | string | Filter nach Job-Status |
| `search` | string | Suche in Titel-Feldern |
| `status` | string | Einzelstatus-Filter (legacy-kompatibel). |
| `statuses` | string | Mehrfachstatus als CSV, z. B. `FINISHED,ERROR`. |
| `search` | string | Suche in Titel-/IMDb-Feldern. |
| `limit` | number | Maximale Anzahl Ergebnisse. |
| `lite` | bool | Ohne Dateisystem-Checks (schneller). |
| `includeChildren` | bool | Child-Jobs (z. B. Serien-/Multipart-Kinder) explizit einbeziehen. |
**Beispiel:**
```text
GET /api/history?status=FINISHED&search=Inception
GET /api/history?statuses=FINISHED,ERROR&search=Inception&limit=50&lite=1
```
**Response:**
**Response (Beispiel):**
```json
{
@@ -30,6 +34,7 @@ GET /api/history?status=FINISHED&search=Inception
"id": 42,
"status": "FINISHED",
"title": "Inception",
"job_kind": "bluray",
"raw_path": "/mnt/raw/Inception - RAW - job-42",
"output_path": "/mnt/movies/Inception (2010)/Inception (2010).mkv",
"mediaType": "bluray",
@@ -52,12 +57,13 @@ Liefert Job-Detail.
| Parameter | Typ | Standard | Beschreibung |
|----------|-----|---------|-------------|
| `includeLogs` | bool | `false` | Prozesslog laden |
| `includeLiveLog` | bool | `false` | alias-artig ebenfalls Prozesslog laden |
| `includeAllLogs` | bool | `false` | vollständiges Log statt Tail |
| `logTailLines` | number | `800` | Tail-Länge falls nicht `includeAllLogs` |
| `includeLogs` | bool | `false` | Prozesslog laden. |
| `includeLiveLog` | bool | `false` | Live-/Tail-Log laden. |
| `includeAllLogs` | bool | `false` | vollständiges Log statt Tail. |
| `logTailLines` | number | `800` | Tail-Länge falls nicht `includeAllLogs`. |
| `lite` | bool | `false` | Detailantwort ohne FS-Checks. |
**Response:**
**Response (Beispiel):**
```json
{
@@ -86,33 +92,9 @@ Liefert Job-Detail.
Sucht RAW-Ordner ohne zugehörigen Job.
**Response:**
```json
{
"rawDir": "/mnt/raw",
"rawDirs": ["/mnt/raw", "/mnt/raw-bluray"],
"rows": [
{
"rawPath": "/mnt/raw/Inception (2010) [tt1375666] - RAW - job-99",
"folderName": "Inception (2010) [tt1375666] - RAW - job-99",
"title": "Inception",
"year": 2010,
"imdbId": "tt1375666",
"folderJobId": 99,
"entryCount": 4,
"hasBlurayStructure": true,
"lastModifiedAt": "2026-03-10T09:00:00.000Z"
}
]
}
```
---
## POST /api/history/orphan-raw/import
Importiert RAW-Ordner als FINISHED-Job.
Importiert einen RAW-Ordner als Job und triggert optional die Analyse des Imports.
**Request:**
@@ -120,12 +102,13 @@ Importiert RAW-Ordner als FINISHED-Job.
{ "rawPath": "/mnt/raw/Inception (2010) [tt1375666] - RAW - job-99" }
```
**Response:**
**Response (Beispiel):**
```json
{
"job": { "id": 77, "status": "FINISHED" },
"uiReset": { "reset": true, "state": "IDLE" }
"activation": { "started": true },
"activationError": null
}
```
@@ -133,26 +116,43 @@ Importiert RAW-Ordner als FINISHED-Job.
## POST /api/history/:id/omdb/assign
Weist OMDb-/Metadaten nachträglich zu.
Weist OMDb-/Filmdaten nachträglich zu.
**Request:**
## POST /api/history/:id/cd/assign
Weist CD-Metadaten (z. B. MusicBrainz) nachträglich zu.
## POST /api/history/:id/error/ack
Quittiert einen Fehlerzustand im Historieneintrag.
---
## GET /api/history/:id/delete-preview
Liefert eine Vorschau der löschbaren Pfade (inkl. Scope auf verknüpfte Jobs).
**Query-Parameter:**
| Parameter | Typ | Standard | Beschreibung |
|----------|-----|---------|-------------|
| `includeRelated` | bool | `true` | Verknüpfte Jobs in die Vorschau einbeziehen. |
**Response (Beispiel):**
```json
{
"imdbId": "tt1375666",
"title": "Inception",
"year": 2010,
"poster": "https://...",
"fromOmdb": true
"preview": {
"jobId": 42,
"relatedJobs": [{ "id": 42 }, { "id": 73 }],
"pathCandidates": {
"raw": [{ "path": "/mnt/raw/...", "exists": true, "isDirectory": true }],
"movie": [{ "path": "/mnt/movies/...", "exists": true, "isDirectory": true }]
}
}
}
```
**Response:**
```json
{ "job": { "id": 42, "imdb_id": "tt1375666" } }
```
---
## POST /api/history/:id/delete-files
@@ -162,23 +162,17 @@ Löscht Dateien eines Jobs, behält DB-Eintrag.
**Request:**
```json
{ "target": "both" }
{
"target": "both",
"includeRelated": true,
"selectedRawPaths": ["/mnt/raw/Inception - RAW - Disc1"],
"selectedMoviePaths": ["/mnt/movies/Inception (2010)"]
}
```
`target`: `raw` | `movie` | `both`
**Response:**
```json
{
"summary": {
"target": "both",
"raw": { "attempted": true, "deleted": true, "filesDeleted": 12, "dirsRemoved": 3, "reason": null },
"movie": { "attempted": true, "deleted": false, "filesDeleted": 0, "dirsRemoved": 0, "reason": "Movie-Datei/Pfad existiert nicht." }
},
"job": { "id": 42 }
}
```
`selectedRawPaths` / `selectedMoviePaths` sind optional und begrenzen die Löschung auf ausgewählte Pfade aus der Vorschau.
---
@@ -189,12 +183,20 @@ Löscht Job aus DB; optional auch Dateien.
**Request:**
```json
{ "target": "none" }
{
"target": "both",
"includeRelated": true,
"resetDriveState": false,
"keepDetectedDevice": true,
"preserveRawForImportJobs": false,
"selectedRawPaths": ["/mnt/raw/Inception - RAW - Disc1"],
"selectedMoviePaths": ["/mnt/movies/Inception (2010)"]
}
```
`target`: `none` | `raw` | `movie` | `both`
**Response:**
**Response (Beispiel):**
```json
{
@@ -209,6 +211,11 @@ Löscht Job aus DB; optional auch Dateien.
"uiReset": {
"reset": true,
"state": "IDLE"
},
"safeguards": {
"containsOrphanRawImportJob": false,
"resetDriveStateApplied": false,
"keepDetectedDeviceApplied": true
}
}
```
@@ -218,4 +225,5 @@ Löscht Job aus DB; optional auch Dateien.
## Hinweise
- Ein aktiver Pipeline-Job kann nicht gelöscht werden (`409`).
- Alle Löschoperationen sind irreversibel.
- Löschoperationen sind irreversibel.
- Bei Serien-/Multipart-Containern steuern `includeRelated` und Pfadselektionen den genauen Scope.
+166 -1
View File
@@ -95,6 +95,18 @@ Erzwingt erneute Laufwerksprüfung.
---
## POST /api/pipeline/rescan-drive
Erzwingt Rescan für ein konkretes Laufwerk.
**Request:**
```json
{ "devicePath": "/dev/sr0" }
```
---
## GET /api/pipeline/omdb/search?q=<query>
OMDb-Titelsuche.
@@ -117,6 +129,78 @@ OMDb-Titelsuche.
---
## GET /api/pipeline/tmdb/series/search?q=<query>&season=<n>
TMDb-Seriensuche (für Serien-Workflow bei DVD/Blu-ray).
---
## GET /api/pipeline/cd/drives
Liefert Snapshot der aktuell bekannten CD-Laufwerke.
---
## GET /api/pipeline/cd/musicbrainz/search?q=<query>
MusicBrainz-Suche für CD-Metadaten.
## GET /api/pipeline/cd/musicbrainz/release/:mbId
Lädt Release-Details zu einer MusicBrainz-ID.
## POST /api/pipeline/cd/select-metadata
Übernimmt CD-Metadaten für einen Job.
**Request (Beispiel):**
```json
{
"jobId": 91,
"title": "Album",
"artist": "Artist",
"year": 2020,
"mbId": "f5093c06-23e3-404f-aeaa-40f72885ee3a",
"coverUrl": "https://...",
"tracks": []
}
```
## POST /api/pipeline/cd/start/:jobId
Startet/queued CD-Rip mit Format-/Script-/Chain-Konfiguration.
---
## POST /api/pipeline/audiobook/upload
Upload von AAX-Datei (Multipart/FormData).
**FormData-Felder:**
- `file` (Pflicht)
- `format` (optional)
- `startImmediately` (optional)
## GET /api/pipeline/audiobook/pending-activation
Zeigt AAX-Jobs mit fehlenden Activation-Bytes.
## POST /api/pipeline/audiobook/start/:jobId
Startet Audiobook-Job mit optionaler Konfiguration.
## GET /api/pipeline/audiobook/jobs
Liefert Audiobook-Jobliste.
## GET /api/pipeline/audiobook/output-tree
Read-only Baumansicht des Audiobook-Ausgabeordners.
---
## POST /api/pipeline/select-metadata
Setzt Metadaten (und optional Playlist) für einen Job.
@@ -135,12 +219,69 @@ Setzt Metadaten (und optional Playlist) für einen Job.
}
```
Wichtige optionale Felder:
- `selectedHandBrakeTitleId` / `selectedHandBrakeTitleIds`: Titel-Auswahl für Review/MediaInfo.
- `metadataProvider`: `omdb` oder `tmdb`.
- `workflowKind`: bei Disc-Jobs typischerweise `film` oder `series`.
- `discNumber`: Pflicht für Serien-Disc-Zuordnung (`workflowKind=series`).
- `duplicateAction`: Duplikatverhalten bei Film-Metadaten (`allow_new` oder `multipart_movie`).
- `existingJobId`: optionaler Referenzjob für `multipart_movie`.
- `existingDiscNumber`: Disc-Nummer des bestehenden Jobs für `multipart_movie`.
**Response:**
```json
{ "job": { "id": 42, "status": "READY_TO_START" } }
```
**Konflikt-Response (Beispiel, HTTP 409):**
```json
{
"message": "Metadaten bereits in der Historie gefunden. Bitte Auswahl übernehmen oder Multipart movie wählen.",
"details": [
{
"code": "METADATA_DUPLICATE_FOUND",
"mediaProfile": "bluray",
"existingJob": {
"id": 17,
"title": "Inception",
"year": 2010,
"status": "FINISHED",
"jobKind": "bluray",
"discNumber": 1,
"isMultipartMovie": false
}
}
]
}
```
**Relevante Fehlercodes (`POST /api/pipeline/select-metadata`):**
| Code | Bedeutung |
|---|---|
| `METADATA_DUPLICATE_FOUND` | Film-Metadaten existieren bereits in der Historie (Konfliktdialog im UI). |
| `MULTIPART_DISC_REQUIRED` | Für Multipart fehlen Disc-Nummern (`discNumber`/`existingDiscNumber`). |
| `MULTIPART_DISC_ALREADY_EXISTS` | Disc-Nummer im Multipart-Container bereits vergeben oder doppelt. |
| `MULTIPART_MEDIA_MISMATCH` | Multipart nur bei gleichem Medientyp (DVD oder Blu-ray). |
| `MULTIPART_SERIES_NOT_ALLOWED` | Multipart ist nur für Film-Jobs erlaubt, nicht für Serien-Workflow. |
| `MULTIPART_METADATA_MISMATCH` | Ausgewählter bestehender Job passt nicht zu den Film-Metadaten. |
| `SERIES_DISC_ALREADY_EXISTS` | Serien-Disc-Nummer innerhalb einer Staffel bereits vorhanden. |
---
## POST /api/pipeline/jobs/:jobId/raw-decision
Trifft Entscheidung bei vorhandenem RAW (`continue` oder `restart` je nach Dialogfluss).
**Request:**
```json
{ "decision": "continue" }
```
---
## POST /api/pipeline/start/:jobId
@@ -233,10 +374,28 @@ Berechnet Review aus RAW neu.
Startet Encoding mit letzter bestätigter Review neu.
## POST /api/pipeline/restart-cd-review/:jobId
Berechnet CD-Review aus vorhandenem RAW neu.
## POST /api/pipeline/resume-ready/:jobId
Lädt `READY_TO_ENCODE`-Job nach Neustart wieder in aktive Session.
## GET /api/pipeline/output-folders/:jobId
Liefert bekannte Output-Ordner entlang der Job-Lineage.
## POST /api/pipeline/delete-output-folders/:jobId
Löscht ausgewählte Output-Ordner.
**Request:**
```json
{ "folderPaths": ["/mnt/movies/Inception (2010)"] }
```
Alle Endpunkte liefern `{ result: ... }` bzw. `{ job: ... }`.
---
@@ -358,12 +517,18 @@ Entfernt Queue-Eintrag.
| `DISC_DETECTED` | Medium erkannt |
| `ANALYZING` | MakeMKV-Analyse läuft |
| `METADATA_SELECTION` | Metadaten-Auswahl |
| `WAITING_FOR_USER_DECISION` | Playlist-Entscheidung erforderlich |
| `WAITING_FOR_USER_DECISION` | Nutzerentscheidung erforderlich (Playlist-Auswahl oder RAW-Entscheidung) |
| `READY_TO_START` | Übergang vor Start |
| `RIPPING` | MakeMKV-Rip läuft |
| `MEDIAINFO_CHECK` | Titel-/Track-Auswertung |
| `READY_TO_ENCODE` | Review bereit |
| `ENCODING` | HandBrake-Encoding läuft |
| `CD_METADATA_SELECTION` | CD-Metadatenauswahl aktiv |
| `CD_READY_TO_RIP` | CD-Job ist startbereit |
| `CD_ANALYZING` | CD-Struktur/Tracks werden vorbereitet |
| `CD_RIPPING` | CD-Ripping läuft |
| `CD_ENCODING` | CD-Encode läuft |
| `FINISHED` | Abgeschlossen |
| `DONE` | Abgeschlossen (v. a. Audiobook/Converter/CD-Varianten) |
| `CANCELLED` | Abgebrochen |
| `ERROR` | Fehler |
+5 -5
View File
@@ -105,7 +105,7 @@ Alle Aktivitäts-Endpunkte geben einen Snapshot zurück:
## Endpunkte
### GET `/api/activities`
### GET `/api/runtime/activities`
Aktuellen Aktivitäts-Snapshot abrufen.
@@ -136,7 +136,7 @@ Aktuellen Aktivitäts-Snapshot abrufen.
---
### POST `/api/activities/:id/cancel`
### POST `/api/runtime/activities/:id/cancel`
Aktive Aktivität abbrechen (nur wenn `canCancel: true`).
@@ -172,7 +172,7 @@ Aktive Aktivität abbrechen (nur wenn `canCancel: true`).
---
### POST `/api/activities/:id/next-step`
### POST `/api/runtime/activities/:id/next-step`
Nächsten Schritt einer Aktivität auslösen (nur wenn `canNextStep: true`).
@@ -201,7 +201,7 @@ Nächsten Schritt einer Aktivität auslösen (nur wenn `canNextStep: true`).
---
### POST `/api/activities/clear-recent`
### POST `/api/runtime/activities/clear-recent`
Alle abgeschlossenen Aktivitäten aus `recent` löschen.
@@ -232,4 +232,4 @@ Gekürzte Ausgaben erhalten den Suffix ` ...[gekürzt]` (bei Inline-Text) bzw. `
## Echtzeit-Updates
Änderungen werden automatisch als [`RUNTIME_ACTIVITY_CHANGED`](websocket.md#runtime_activity_changed) WebSocket-Event gesendet. Die Frontend-Komponente braucht `GET /api/activities` nur beim initialen Laden aufzurufen.
Änderungen werden automatisch als [`RUNTIME_ACTIVITY_CHANGED`](websocket.md#runtime_activity_changed) WebSocket-Event gesendet. Die Frontend-Komponente braucht `GET /api/runtime/activities` nur beim initialen Laden aufzurufen.
+86
View File
@@ -336,3 +336,89 @@ Body mit beliebigen Feldern aus `POST`, Response `{ "preset": { ... } }`.
### DELETE /api/settings/user-presets/:id
Response `{ "removed": { ... } }`.
---
## Weitere Endpunkte
### GET /api/settings/effective-paths
Liefert aufgelöste, effektiv genutzte Pfade aus den Settings (für UI- und Diagnosezwecke).
### POST /api/settings/coverart/recover
Startet eine manuelle Coverart-Recovery.
**Response (Beispiel):**
```json
{
"result": { "started": true },
"scheduler": { "enabled": true }
}
```
---
## Activation Bytes (AAX)
### GET /api/settings/activation-bytes
Liest gecachte AAX-Activation-Bytes.
### POST /api/settings/activation-bytes
Speichert Activation-Bytes.
**Request:**
```json
{
"checksum": "abc123...",
"activationBytes": "1a2b3c4d"
}
```
---
## Laufwerke
### GET /api/settings/drives
Liefert erkannte optische Laufwerke (`/dev/...`) inkl. MakeMKV-Disc-Index.
### POST /api/settings/drives/force-unlock
Erzwingt Entsperren aktiver Laufwerkslocks.
Hinweis: Expertenmodus (`ui_expert_mode`) ist erforderlich, sonst `403`.
**Request (ein Laufwerk):**
```json
{ "devicePath": "/dev/sr0" }
```
**Request (alle):**
```json
{ "all": true }
```
---
## UI Preferences
### GET /api/settings/prefs/:key
Liest einen persistierten UI-Preference-Wert.
### PUT /api/settings/prefs/:key
Speichert einen persistierten UI-Preference-Wert.
**Request:**
```json
{ "value": "{\"columns\":[\"id\",\"status\"]}" }
```