Bugfix and Docs
This commit is contained in:
@@ -1,16 +1,12 @@
|
||||
# Cron API
|
||||
|
||||
Ripster enthält ein eingebautes Cron-System, mit dem **Skripte** und **Skript-Ketten** zeitgesteuert oder manuell ausgeführt werden können. Der Cron-Dienst benötigt keine externen Pakete – der Cron-Expression-Parser ist vollständig im Backend implementiert.
|
||||
Ripster enthält ein eingebautes Cron-System für Skripte und Skript-Ketten (`sourceType: script|chain`).
|
||||
|
||||
---
|
||||
|
||||
## Endpunkte
|
||||
## GET /api/crons
|
||||
|
||||
### `GET /api/crons`
|
||||
|
||||
Alle konfigurierten Cron-Jobs auflisten.
|
||||
|
||||
**Antwort:**
|
||||
Listet alle Cron-Jobs.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -21,13 +17,14 @@ Alle konfigurierten Cron-Jobs auflisten.
|
||||
"cronExpression": "0 2 * * *",
|
||||
"sourceType": "script",
|
||||
"sourceId": 3,
|
||||
"sourceName": "Backup-Skript",
|
||||
"enabled": true,
|
||||
"pushoverEnabled": true,
|
||||
"lastRunAt": "2026-03-09T02:00:00.000Z",
|
||||
"lastRunAt": "2026-03-10T02:00:00.000Z",
|
||||
"lastRunStatus": "success",
|
||||
"nextRunAt": "2026-03-10T02:00:00.000Z",
|
||||
"nextRunAt": "2026-03-11T02:00:00.000Z",
|
||||
"createdAt": "2026-03-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-03-09T02:00:00.000Z"
|
||||
"updatedAt": "2026-03-10T02:00:05.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -35,11 +32,9 @@ Alle konfigurierten Cron-Jobs auflisten.
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/crons`
|
||||
## POST /api/crons
|
||||
|
||||
Neuen Cron-Job anlegen.
|
||||
|
||||
**Body:**
|
||||
Erstellt Cron-Job.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -52,16 +47,25 @@ Neuen Cron-Job anlegen.
|
||||
}
|
||||
```
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|------|-----|---------|-------------|
|
||||
| `name` | string | ✓ | Anzeigename |
|
||||
| `cronExpression` | string | ✓ | 5-Felder-Cron-Ausdruck (Minute Stunde Tag Monat Wochentag) |
|
||||
| `sourceType` | string | ✓ | `"script"` oder `"chain"` |
|
||||
| `sourceId` | number | ✓ | ID des Skripts bzw. der Kette |
|
||||
| `enabled` | boolean | – | Aktiviert (default: `true`) |
|
||||
| `pushoverEnabled` | boolean | – | PushOver-Benachrichtigung nach Ausführung (default: `true`) |
|
||||
Response: `201` mit `{ "job": { ... } }`
|
||||
|
||||
**Antwort:** `201 Created`
|
||||
---
|
||||
|
||||
## GET /api/crons/:id
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{ "job": { "id": 1, "name": "..." } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PUT /api/crons/:id
|
||||
|
||||
Aktualisiert Cron-Job. Felder wie bei `POST`.
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{ "job": { ... } }
|
||||
@@ -69,53 +73,27 @@ Neuen Cron-Job anlegen.
|
||||
|
||||
---
|
||||
|
||||
### `GET /api/crons/:id`
|
||||
## DELETE /api/crons/:id
|
||||
|
||||
Einzelnen Cron-Job abrufen.
|
||||
|
||||
**Antwort:**
|
||||
Response:
|
||||
|
||||
```json
|
||||
{ "job": { ... } }
|
||||
{ "removed": { "id": 1, "name": "Nachtlauf Backup" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `PUT /api/crons/:id`
|
||||
## GET /api/crons/:id/logs
|
||||
|
||||
Cron-Job aktualisieren. Body-Felder entsprechen `POST /api/crons`.
|
||||
|
||||
**Antwort:**
|
||||
|
||||
```json
|
||||
{ "job": { ... } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `DELETE /api/crons/:id`
|
||||
|
||||
Cron-Job löschen.
|
||||
|
||||
**Antwort:**
|
||||
|
||||
```json
|
||||
{ "removed": { "id": 1 } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `GET /api/crons/:id/logs`
|
||||
|
||||
Ausführungs-Logs eines Cron-Jobs abrufen.
|
||||
Liefert Ausführungs-Logs.
|
||||
|
||||
**Query-Parameter:**
|
||||
|
||||
| Parameter | Typ | Default | Beschreibung |
|
||||
|-----------|-----|---------|-------------|
|
||||
| `limit` | number | 20 | Anzahl Einträge (max. 100) |
|
||||
| `limit` | number | `20` | Anzahl Einträge, max. `100` |
|
||||
|
||||
**Antwort:**
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -123,62 +101,54 @@ Ausführungs-Logs eines Cron-Jobs abrufen.
|
||||
{
|
||||
"id": 42,
|
||||
"cronJobId": 1,
|
||||
"startedAt": "2026-03-09T02:00:01.000Z",
|
||||
"finishedAt": "2026-03-09T02:00:05.000Z",
|
||||
"startedAt": "2026-03-10T02:00:01.000Z",
|
||||
"finishedAt": "2026-03-10T02:00:05.000Z",
|
||||
"status": "success",
|
||||
"exitCode": 0,
|
||||
"stdout": "Backup abgeschlossen.",
|
||||
"stderr": "",
|
||||
"triggeredBy": "cron"
|
||||
"output": "Backup abgeschlossen.",
|
||||
"errorMessage": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Feld | Beschreibung |
|
||||
|------|-------------|
|
||||
| `status` | `"success"`, `"error"` oder `"running"` |
|
||||
| `triggeredBy` | `"cron"` (zeitgesteuert) oder `"manual"` (manuell ausgelöst) |
|
||||
`status`: `running` | `success` | `error`
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/crons/:id/run`
|
||||
## POST /api/crons/:id/run
|
||||
|
||||
Cron-Job sofort manuell auslösen (unabhängig vom Zeitplan).
|
||||
Triggert Job manuell (asynchron).
|
||||
|
||||
**Antwort:**
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"exitCode": 0,
|
||||
"stdout": "...",
|
||||
"stderr": ""
|
||||
}
|
||||
{ "triggered": true, "cronJobId": 1 }
|
||||
```
|
||||
|
||||
Wenn Job bereits läuft: `409`.
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/crons/validate-expression`
|
||||
## POST /api/crons/validate-expression
|
||||
|
||||
Cron-Ausdruck validieren und nächsten Ausführungszeitpunkt berechnen.
|
||||
Validiert 5-Felder-Cron-Ausdruck und berechnet nächsten Lauf.
|
||||
|
||||
**Body:**
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{ "cronExpression": "*/15 * * * *" }
|
||||
```
|
||||
|
||||
**Antwort (gültig):**
|
||||
**Gültige Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"nextRunAt": "2026-03-09T14:15:00.000Z"
|
||||
"nextRunAt": "2026-03-10T14:15:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Antwort (ungültig):**
|
||||
**Ungültige Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -190,54 +160,23 @@ Cron-Ausdruck validieren und nächsten Ausführungszeitpunkt berechnen.
|
||||
|
||||
---
|
||||
|
||||
## Cron-Expression-Format
|
||||
## Cron-Format
|
||||
|
||||
Ripster verwendet **5-Felder-Cron-Ausdrücke** (kein Sekunden-Feld):
|
||||
Ripster unterstützt 5 Felder:
|
||||
|
||||
```
|
||||
┌───────────── Minute (0-59)
|
||||
│ ┌────────── Stunde (0-23)
|
||||
│ │ ┌─────── Tag (1-31)
|
||||
│ │ │ ┌──── Monat (1-12)
|
||||
│ │ │ │ ┌─ Wochentag (0-7, 0 und 7 = Sonntag)
|
||||
│ │ │ │ │
|
||||
* * * * *
|
||||
```text
|
||||
Minute Stunde Tag Monat Wochentag
|
||||
```
|
||||
|
||||
### Beispiele
|
||||
Beispiele:
|
||||
|
||||
| Ausdruck | Beschreibung |
|
||||
|----------|-------------|
|
||||
| `0 2 * * *` | Täglich um 02:00 Uhr |
|
||||
| `*/15 * * * *` | Alle 15 Minuten |
|
||||
| `0 6 * * 1-5` | Montag–Freitag um 06:00 Uhr |
|
||||
| `30 23 * * 0` | Sonntags um 23:30 Uhr |
|
||||
| `0 0 1 * *` | Erster Tag des Monats um Mitternacht |
|
||||
|
||||
### Unterstützte Syntax
|
||||
|
||||
| Syntax | Bedeutung |
|
||||
|--------|----------|
|
||||
| `*` | Jeder Wert |
|
||||
| `*/n` | Jeder n-te Wert (Step) |
|
||||
| `a-b` | Bereich von a bis b |
|
||||
| `a,b,c` | Liste von Werten |
|
||||
| Kombinierbar | z. B. `1,5-10,*/3` |
|
||||
- `0 2 * * *` täglich 02:00
|
||||
- `*/15 * * * *` alle 15 Minuten
|
||||
- `0 6 * * 1-5` Mo-Fr 06:00
|
||||
|
||||
---
|
||||
|
||||
## WebSocket-Event
|
||||
## WebSocket-Events zu Cron
|
||||
|
||||
Bei Änderungen an Cron-Jobs (Anlegen, Aktualisieren, Löschen) wird ein `CRON_JOBS_UPDATED`-Event gesendet:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "CRON_JOBS_UPDATED",
|
||||
"payload": {
|
||||
"action": "created",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`action` ist `"created"`, `"updated"` oder `"deleted"`.
|
||||
- `CRON_JOBS_UPDATED` bei Create/Update/Delete
|
||||
- `CRON_JOB_UPDATED` bei Laufzeitstatus (`running` -> `success|error`)
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# History API
|
||||
|
||||
Endpunkte für die Job-Histoire, Dateimanagement und Orphan-Import.
|
||||
Endpunkte für Job-Historie, Orphan-Import und Löschoperationen.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/history
|
||||
|
||||
Gibt eine Liste aller Jobs zurück, optional gefiltert.
|
||||
Liefert Jobs (optionale Filter).
|
||||
|
||||
**Query-Parameter:**
|
||||
|
||||
| Parameter | Typ | Beschreibung |
|
||||
|----------|-----|-------------|
|
||||
| `status` | string | Filtert nach Status (z.B. `FINISHED`, `ERROR`) |
|
||||
| `search` | string | Sucht in Filmtiteln |
|
||||
| `status` | string | Filter nach Job-Status |
|
||||
| `search` | string | Suche in Titel-Feldern |
|
||||
|
||||
**Beispiel:**
|
||||
|
||||
```
|
||||
```text
|
||||
GET /api/history?status=FINISHED&search=Inception
|
||||
```
|
||||
|
||||
@@ -30,17 +30,15 @@ GET /api/history?status=FINISHED&search=Inception
|
||||
"id": 42,
|
||||
"status": "FINISHED",
|
||||
"title": "Inception",
|
||||
"imdb_id": "tt1375666",
|
||||
"omdb_year": "2010",
|
||||
"omdb_type": "movie",
|
||||
"omdb_poster": "https://...",
|
||||
"raw_path": "/mnt/nas/raw/Inception_t00.mkv",
|
||||
"output_path": "/mnt/nas/movies/Inception (2010).mkv",
|
||||
"created_at": "2024-01-15T10:00:00.000Z",
|
||||
"updated_at": "2024-01-15T12:30:00.000Z"
|
||||
"raw_path": "/mnt/raw/Inception - RAW - job-42",
|
||||
"output_path": "/mnt/movies/Inception (2010)/Inception (2010).mkv",
|
||||
"mediaType": "bluray",
|
||||
"ripSuccessful": true,
|
||||
"encodeSuccess": true,
|
||||
"created_at": "2026-03-10T08:00:00.000Z",
|
||||
"updated_at": "2026-03-10T10:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,34 +46,37 @@ GET /api/history?status=FINISHED&search=Inception
|
||||
|
||||
## GET /api/history/:id
|
||||
|
||||
Gibt Detail-Informationen für einen einzelnen Job zurück.
|
||||
|
||||
**URL-Parameter:** `id` – Job-ID
|
||||
Liefert Job-Detail.
|
||||
|
||||
**Query-Parameter:**
|
||||
|
||||
| Parameter | Typ | Standard | Beschreibung |
|
||||
|----------|-----|---------|-------------|
|
||||
| `includeLogs` | boolean | `false` | Log-Inhalte einschließen |
|
||||
| `includeLiveLog` | boolean | `false` | Aktuellen Live-Log einschließen |
|
||||
| `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` |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 42,
|
||||
"status": "FINISHED",
|
||||
"title": "Inception",
|
||||
"imdb_id": "tt1375666",
|
||||
"encode_plan": { ... },
|
||||
"makemkv_output": { ... },
|
||||
"mediainfo_output": { ... },
|
||||
"handbrake_log": "/path/to/log",
|
||||
"logs": {
|
||||
"handbrake": "Encoding: task 1 of 1, 100.0%\n..."
|
||||
},
|
||||
"created_at": "2024-01-15T10:00:00.000Z",
|
||||
"updated_at": "2024-01-15T12:30:00.000Z"
|
||||
"job": {
|
||||
"id": 42,
|
||||
"status": "FINISHED",
|
||||
"makemkvInfo": {},
|
||||
"mediainfoInfo": {},
|
||||
"handbrakeInfo": {},
|
||||
"encodePlan": {},
|
||||
"log": "...",
|
||||
"log_count": 1,
|
||||
"logMeta": {
|
||||
"loaded": true,
|
||||
"total": 800,
|
||||
"returned": 800,
|
||||
"truncated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -83,14 +84,19 @@ Gibt Detail-Informationen für einen einzelnen Job zurück.
|
||||
|
||||
## GET /api/history/database
|
||||
|
||||
Gibt alle rohen Datenbankzeilen zurück (Debug-Ansicht).
|
||||
Debug-Ansicht der DB-Zeilen (angereichert).
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"jobs": [ { "id": 1, "status": "FINISHED", ... } ],
|
||||
"total": 15
|
||||
"rows": [
|
||||
{
|
||||
"id": 42,
|
||||
"status": "FINISHED",
|
||||
"rawFolderName": "Inception - RAW - job-42"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -98,18 +104,25 @@ Gibt alle rohen Datenbankzeilen zurück (Debug-Ansicht).
|
||||
|
||||
## GET /api/history/orphan-raw
|
||||
|
||||
Findet Raw-Ordner, die nicht als Jobs in der Datenbank registriert sind.
|
||||
Sucht RAW-Ordner ohne zugehörigen Job.
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"orphans": [
|
||||
"rawDir": "/mnt/raw",
|
||||
"rawDirs": ["/mnt/raw", "/mnt/raw-bluray"],
|
||||
"rows": [
|
||||
{
|
||||
"path": "/mnt/nas/raw/UnknownMovie_2023-12-01",
|
||||
"size": "45.2 GB",
|
||||
"modifiedAt": "2023-12-01T15:00:00.000Z",
|
||||
"files": ["t00.mkv", "t01.mkv"]
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -119,35 +132,28 @@ Findet Raw-Ordner, die nicht als Jobs in der Datenbank registriert sind.
|
||||
|
||||
## POST /api/history/orphan-raw/import
|
||||
|
||||
Importiert einen Orphan-Raw-Ordner als Job in die Datenbank.
|
||||
Importiert RAW-Ordner als FINISHED-Job.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/mnt/nas/raw/UnknownMovie_2023-12-01"
|
||||
}
|
||||
{ "rawPath": "/mnt/raw/Inception (2010) [tt1375666] - RAW - job-99" }
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"jobId": 99,
|
||||
"message": "Orphan-Ordner als Job importiert"
|
||||
"job": { "id": 77, "status": "FINISHED" },
|
||||
"uiReset": { "reset": true, "state": "IDLE" }
|
||||
}
|
||||
```
|
||||
|
||||
Nach dem Import kann dem Job über `/api/history/:id/omdb/assign` Metadaten zugewiesen werden.
|
||||
|
||||
---
|
||||
|
||||
## POST /api/history/:id/omdb/assign
|
||||
|
||||
Weist einem bestehenden Job OMDb-Metadaten nachträglich zu.
|
||||
|
||||
**URL-Parameter:** `id` – Job-ID
|
||||
Weist OMDb-/Metadaten nachträglich zu.
|
||||
|
||||
**Request:**
|
||||
|
||||
@@ -155,44 +161,42 @@ Weist einem bestehenden Job OMDb-Metadaten nachträglich zu.
|
||||
{
|
||||
"imdbId": "tt1375666",
|
||||
"title": "Inception",
|
||||
"year": "2010",
|
||||
"type": "movie",
|
||||
"poster": "https://..."
|
||||
"year": 2010,
|
||||
"poster": "https://...",
|
||||
"fromOmdb": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "ok": true }
|
||||
{ "job": { "id": 42, "imdb_id": "tt1375666" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/history/:id/delete-files
|
||||
|
||||
Löscht die Dateien eines Jobs (Raw und/oder Output), behält den Job-Eintrag.
|
||||
|
||||
**URL-Parameter:** `id` – Job-ID
|
||||
Löscht Dateien eines Jobs, behält DB-Eintrag.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"deleteRaw": true,
|
||||
"deleteOutput": false
|
||||
}
|
||||
{ "target": "both" }
|
||||
```
|
||||
|
||||
`target`: `raw` | `movie` | `both`
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"deleted": {
|
||||
"raw": "/mnt/nas/raw/Inception_t00.mkv",
|
||||
"output": null
|
||||
}
|
||||
"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 }
|
||||
}
|
||||
```
|
||||
|
||||
@@ -200,23 +204,38 @@ Löscht die Dateien eines Jobs (Raw und/oder Output), behält den Job-Eintrag.
|
||||
|
||||
## POST /api/history/:id/delete
|
||||
|
||||
Löscht den Job-Eintrag aus der Datenbank, optional auch die Dateien.
|
||||
|
||||
**URL-Parameter:** `id` – Job-ID
|
||||
Löscht Job aus DB; optional auch Dateien.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"deleteFiles": true
|
||||
}
|
||||
{ "target": "none" }
|
||||
```
|
||||
|
||||
`target`: `none` | `raw` | `movie` | `both`
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "ok": true, "message": "Job gelöscht" }
|
||||
{
|
||||
"deleted": true,
|
||||
"jobId": 42,
|
||||
"fileTarget": "both",
|
||||
"fileSummary": {
|
||||
"target": "both",
|
||||
"raw": { "filesDeleted": 10 },
|
||||
"movie": { "filesDeleted": 1 }
|
||||
},
|
||||
"uiReset": {
|
||||
"reset": true,
|
||||
"state": "IDLE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! warning "Unwiderruflich"
|
||||
Das Löschen von Jobs und Dateien ist nicht rückgängig zu machen.
|
||||
---
|
||||
|
||||
## Hinweise
|
||||
|
||||
- Ein aktiver Pipeline-Job kann nicht gelöscht werden (`409`).
|
||||
- Alle Löschoperationen sind irreversibel.
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
# API-Referenz
|
||||
|
||||
Ripster bietet eine **REST-API** für alle Operationen sowie einen **WebSocket-Endpunkt** für Echtzeit-Updates.
|
||||
Ripster bietet eine REST-API für Steuerung/Verwaltung sowie einen WebSocket-Endpunkt für Echtzeit-Updates.
|
||||
|
||||
---
|
||||
|
||||
## Basis-URL
|
||||
|
||||
```
|
||||
```text
|
||||
http://localhost:3001
|
||||
```
|
||||
|
||||
Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
API-Prefix: `/api`
|
||||
|
||||
Beispiele:
|
||||
|
||||
- `GET /api/health`
|
||||
- `GET /api/pipeline/state`
|
||||
|
||||
---
|
||||
|
||||
@@ -18,11 +23,19 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-heart-pulse: **Health**
|
||||
|
||||
---
|
||||
|
||||
Service-Liveness.
|
||||
|
||||
`GET /api/health`
|
||||
|
||||
- :material-pipe: **Pipeline API**
|
||||
|
||||
---
|
||||
|
||||
Pipeline-Steuerung: Analyse starten, Metadaten setzen, Ripping und Encoding steuern.
|
||||
Analyse, Start/Retry/Cancel, Queue, Re-Encode.
|
||||
|
||||
[:octicons-arrow-right-24: Pipeline API](pipeline.md)
|
||||
|
||||
@@ -30,7 +43,7 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
---
|
||||
|
||||
Einstellungen lesen und schreiben.
|
||||
Einstellungen, Skripte/Ketten, User-Presets.
|
||||
|
||||
[:octicons-arrow-right-24: Settings API](settings.md)
|
||||
|
||||
@@ -38,7 +51,7 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
---
|
||||
|
||||
Job-Geschichte abfragen, Jobs löschen, Orphan-Ordner importieren.
|
||||
Job-Historie, Orphan-Import, Löschoperationen.
|
||||
|
||||
[:octicons-arrow-right-24: History API](history.md)
|
||||
|
||||
@@ -46,7 +59,7 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
---
|
||||
|
||||
Cron-Jobs verwalten, manuell auslösen und Ausführungs-Logs abrufen.
|
||||
Zeitgesteuerte Skript-/Kettenausführung.
|
||||
|
||||
[:octicons-arrow-right-24: Cron API](crons.md)
|
||||
|
||||
@@ -54,7 +67,7 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
---
|
||||
|
||||
Echtzeit-Events für Pipeline-Status, Fortschritt und Disc-Erkennung.
|
||||
Pipeline-, Queue-, Disk-, Settings-, Cron- und Monitoring-Events.
|
||||
|
||||
[:octicons-arrow-right-24: WebSocket](websocket.md)
|
||||
|
||||
@@ -64,30 +77,41 @@ Konfigurierbar über die Umgebungsvariable `PORT`.
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
Die API hat **keine Authentifizierung**. Sie ist für den Einsatz im lokalen Netzwerk konzipiert.
|
||||
|
||||
!!! warning "Produktionsbetrieb"
|
||||
Falls Ripster öffentlich erreichbar sein soll, schütze die API mit einem Reverse-Proxy (z. B. nginx mit Basic Auth oder OAuth).
|
||||
Es gibt keine eingebaute Authentifizierung. Ripster ist für lokalen Betrieb gedacht.
|
||||
|
||||
---
|
||||
|
||||
## Fehlerformat
|
||||
|
||||
Alle API-Fehler werden im folgenden Format zurückgegeben:
|
||||
Fehler werden zentral als JSON geliefert:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Job nicht gefunden",
|
||||
"details": "Kein Job mit ID 999 vorhanden"
|
||||
"error": {
|
||||
"message": "Job nicht gefunden.",
|
||||
"statusCode": 404,
|
||||
"reqId": "req_...",
|
||||
"details": [
|
||||
{
|
||||
"field": "name",
|
||||
"message": "Name darf nicht leer sein."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
HTTP-Statuscodes:
|
||||
`details` ist optional (z. B. bei Validierungsfehlern).
|
||||
|
||||
---
|
||||
|
||||
## Häufige Statuscodes
|
||||
|
||||
| Code | Bedeutung |
|
||||
|-----|-----------|
|
||||
|------|-----------|
|
||||
| `200` | Erfolg |
|
||||
| `400` | Ungültige Anfrage |
|
||||
| `201` | Ressource erstellt |
|
||||
| `400` | Ungültige Anfrage / Validierungsfehler |
|
||||
| `404` | Ressource nicht gefunden |
|
||||
| `409` | Konflikt (z.B. Pipeline bereits aktiv) |
|
||||
| `500` | Interner Serverfehler |
|
||||
| `409` | Konflikt (z. B. falscher Pipeline-Zustand, Job läuft bereits) |
|
||||
| `500` | Interner Fehler |
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Pipeline API
|
||||
|
||||
Alle Endpunkte zur Steuerung des Ripster-Workflows.
|
||||
Endpunkte zur Steuerung des Pipeline-Workflows.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/pipeline/state
|
||||
|
||||
Liefert den aktuellen Pipeline-Snapshot.
|
||||
Liefert aktuellen Pipeline- und Hardware-Monitoring-Snapshot.
|
||||
|
||||
**Response:**
|
||||
**Response (Beispiel):**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -17,45 +17,46 @@ Liefert den aktuellen Pipeline-Snapshot.
|
||||
"activeJobId": 42,
|
||||
"progress": 0,
|
||||
"eta": null,
|
||||
"statusText": "Mediainfo geladen - bitte bestätigen",
|
||||
"statusText": "Mediainfo bestätigt - Encode manuell starten",
|
||||
"context": {
|
||||
"jobId": 42
|
||||
},
|
||||
"jobProgress": {
|
||||
"42": {
|
||||
"state": "MEDIAINFO_CHECK",
|
||||
"progress": 68.5,
|
||||
"eta": null,
|
||||
"statusText": "MEDIAINFO_CHECK 68.50%"
|
||||
}
|
||||
},
|
||||
"queue": {
|
||||
"maxParallelJobs": 1,
|
||||
"runningCount": 0,
|
||||
"queuedCount": 0,
|
||||
"runningCount": 1,
|
||||
"queuedCount": 2,
|
||||
"runningJobs": [],
|
||||
"queuedJobs": []
|
||||
}
|
||||
},
|
||||
"hardwareMonitoring": {
|
||||
"enabled": true,
|
||||
"intervalMs": 5000,
|
||||
"updatedAt": "2026-03-10T09:00:00.000Z",
|
||||
"sample": {
|
||||
"cpu": {},
|
||||
"memory": {},
|
||||
"gpu": {},
|
||||
"storage": {}
|
||||
},
|
||||
"error": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Pipeline-Zustände:**
|
||||
|
||||
| Wert | Beschreibung |
|
||||
|------|-------------|
|
||||
| `IDLE` | Wartet auf Medium |
|
||||
| `DISC_DETECTED` | Medium erkannt, wartet auf Analyse-Start |
|
||||
| `METADATA_SELECTION` | Metadaten-Dialog aktiv |
|
||||
| `WAITING_FOR_USER_DECISION` | Manuelle Playlist-Auswahl erforderlich |
|
||||
| `READY_TO_START` | Übergang/Fallback vor Start |
|
||||
| `RIPPING` | MakeMKV läuft |
|
||||
| `MEDIAINFO_CHECK` | HandBrake-Scan + Plan-Erstellung |
|
||||
| `READY_TO_ENCODE` | Review bereit |
|
||||
| `ENCODING` | HandBrake-Encoding läuft (inkl. Post-Skripte) |
|
||||
| `FINISHED` | Abgeschlossen |
|
||||
| `CANCELLED` | Vom Benutzer abgebrochen |
|
||||
| `ERROR` | Fehler |
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/analyze
|
||||
|
||||
Startet die Analyse für die aktuell erkannte Disc.
|
||||
|
||||
**Request:** kein Body
|
||||
Startet Disc-Analyse und legt Job an.
|
||||
|
||||
**Response:**
|
||||
|
||||
@@ -73,14 +74,21 @@ Startet die Analyse für die aktuell erkannte Disc.
|
||||
|
||||
## POST /api/pipeline/rescan-disc
|
||||
|
||||
Erzwingt eine erneute Laufwerksprüfung.
|
||||
Erzwingt erneute Laufwerksprüfung.
|
||||
|
||||
**Response (Beispiel):**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"emitted": "discInserted"
|
||||
"present": true,
|
||||
"changed": true,
|
||||
"emitted": "discInserted",
|
||||
"device": {
|
||||
"path": "/dev/sr0",
|
||||
"discLabel": "INCEPTION",
|
||||
"mediaProfile": "bluray"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -89,7 +97,7 @@ Erzwingt eine erneute Laufwerksprüfung.
|
||||
|
||||
## GET /api/pipeline/omdb/search?q=<query>
|
||||
|
||||
Sucht OMDb-Titel.
|
||||
OMDb-Titelsuche.
|
||||
|
||||
**Response:**
|
||||
|
||||
@@ -111,7 +119,7 @@ Sucht OMDb-Titel.
|
||||
|
||||
## POST /api/pipeline/select-metadata
|
||||
|
||||
Setzt Metadaten (und optional Playlist-Entscheidung).
|
||||
Setzt Metadaten (und optional Playlist) für einen Job.
|
||||
|
||||
**Request:**
|
||||
|
||||
@@ -127,38 +135,35 @@ Setzt Metadaten (und optional Playlist-Entscheidung).
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "job": { ... } }`
|
||||
**Response:**
|
||||
|
||||
!!! note "Startlogik"
|
||||
Nach Metadaten-Bestätigung wird der nächste Schritt automatisch ausgelöst (`startPreparedJob`).
|
||||
Der Job startet direkt oder wird in die Queue eingereiht.
|
||||
```json
|
||||
{ "job": { "id": 42, "status": "READY_TO_START" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/start/:jobId
|
||||
|
||||
Startet einen vorbereiteten Job manuell (z. B. Fallback/Queue-Szenario).
|
||||
Startet vorbereiteten Job oder queued ihn (je nach Parallel-Limit).
|
||||
|
||||
**Response (Beispiel):**
|
||||
**Mögliche Responses:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"started": true,
|
||||
"stage": "RIPPING"
|
||||
}
|
||||
}
|
||||
{ "result": { "started": true, "stage": "RIPPING" } }
|
||||
```
|
||||
|
||||
Mögliche `stage`-Werte sind u. a. `RIPPING`, `MEDIAINFO_CHECK`, `ENCODING`.
|
||||
```json
|
||||
{ "result": { "queued": true, "started": false, "queuePosition": 2, "action": "START_PREPARED" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/confirm-encode/:jobId
|
||||
|
||||
Bestätigt Review-Auswahl (Titel/Tracks/Post-Skripte).
|
||||
Bestätigt Review-Auswahl (Tracks, Pre/Post-Skripte/Ketten, User-Preset).
|
||||
|
||||
**Request:**
|
||||
**Request (typisch):**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -169,78 +174,70 @@ Bestätigt Review-Auswahl (Titel/Tracks/Post-Skripte).
|
||||
"subtitleTrackIds": [3]
|
||||
}
|
||||
},
|
||||
"selectedPreEncodeScriptIds": [1],
|
||||
"selectedPostEncodeScriptIds": [2, 7],
|
||||
"selectedPreEncodeChainIds": [3],
|
||||
"selectedPostEncodeChainIds": [4],
|
||||
"selectedUserPresetId": 5,
|
||||
"skipPipelineStateUpdate": false
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "job": { ... } }`
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "job": { "id": 42, "encode_review_confirmed": 1 } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/cancel
|
||||
|
||||
Bricht laufenden Job ab oder entfernt einen Queue-Eintrag.
|
||||
Bricht laufenden Job ab oder entfernt Queue-Eintrag.
|
||||
|
||||
**Request (optional):**
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": 42
|
||||
}
|
||||
{ "jobId": 42 }
|
||||
```
|
||||
|
||||
**Response (Beispiel):**
|
||||
**Mögliche Responses:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"cancelled": true,
|
||||
"queuedOnly": false,
|
||||
"jobId": 42
|
||||
}
|
||||
}
|
||||
{ "result": { "cancelled": true, "queuedOnly": true, "jobId": 42 } }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "result": { "cancelled": true, "queuedOnly": false, "jobId": 42 } }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "result": { "cancelled": true, "queuedOnly": false, "pending": true, "jobId": 42 } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/retry/:jobId
|
||||
|
||||
Startet einen Job aus `ERROR`/`CANCELLED` erneut (oder reiht ihn in die Queue ein).
|
||||
|
||||
**Response:** `{ "result": { ... } }`
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/resume-ready/:jobId
|
||||
|
||||
Lädt einen `READY_TO_ENCODE`-Job nach Neustart wieder in die aktive Session.
|
||||
|
||||
**Response:** `{ "job": { ... } }`
|
||||
|
||||
---
|
||||
Retry für `ERROR`/`CANCELLED`-Jobs (oder Queue-Einreihung).
|
||||
|
||||
## POST /api/pipeline/reencode/:jobId
|
||||
|
||||
Startet Re-Encode aus bestehendem RAW.
|
||||
|
||||
**Response:** `{ "result": { ... } }`
|
||||
|
||||
---
|
||||
|
||||
## POST /api/pipeline/restart-review/:jobId
|
||||
|
||||
Berechnet die Review aus vorhandenem RAW neu.
|
||||
|
||||
**Response:** `{ "result": { ... } }`
|
||||
|
||||
---
|
||||
Berechnet Review aus RAW neu.
|
||||
|
||||
## POST /api/pipeline/restart-encode/:jobId
|
||||
|
||||
Startet Encoding mit der zuletzt bestätigten Auswahl neu.
|
||||
Startet Encoding mit letzter bestätigter Review neu.
|
||||
|
||||
**Response:** `{ "result": { ... } }`
|
||||
## POST /api/pipeline/resume-ready/:jobId
|
||||
|
||||
Lädt `READY_TO_ENCODE`-Job nach Neustart wieder in aktive Session.
|
||||
|
||||
Alle Endpunkte liefern `{ result: ... }` bzw. `{ job: ... }`.
|
||||
|
||||
---
|
||||
|
||||
@@ -248,9 +245,51 @@ Startet Encoding mit der zuletzt bestätigten Auswahl neu.
|
||||
|
||||
### GET /api/pipeline/queue
|
||||
|
||||
Liefert den aktuellen Queue-Status.
|
||||
Liefert Queue-Snapshot.
|
||||
|
||||
**Response:** `{ "queue": { ... } }`
|
||||
```json
|
||||
{
|
||||
"queue": {
|
||||
"maxParallelJobs": 1,
|
||||
"runningCount": 1,
|
||||
"queuedCount": 3,
|
||||
"runningJobs": [
|
||||
{
|
||||
"jobId": 41,
|
||||
"title": "Inception",
|
||||
"status": "ENCODING",
|
||||
"lastState": "ENCODING"
|
||||
}
|
||||
],
|
||||
"queuedJobs": [
|
||||
{
|
||||
"entryId": 11,
|
||||
"position": 1,
|
||||
"type": "job",
|
||||
"jobId": 42,
|
||||
"action": "START_PREPARED",
|
||||
"actionLabel": "Start",
|
||||
"title": "Matrix",
|
||||
"status": "READY_TO_ENCODE",
|
||||
"lastState": "READY_TO_ENCODE",
|
||||
"hasScripts": true,
|
||||
"hasChains": false,
|
||||
"enqueuedAt": "2026-03-10T09:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"entryId": 12,
|
||||
"position": 2,
|
||||
"type": "wait",
|
||||
"waitSeconds": 30,
|
||||
"title": "Warten 30s",
|
||||
"status": "QUEUED",
|
||||
"enqueuedAt": "2026-03-10T09:01:00.000Z"
|
||||
}
|
||||
],
|
||||
"updatedAt": "2026-03-10T09:01:02.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST /api/pipeline/queue/reorder
|
||||
|
||||
@@ -260,8 +299,71 @@ Sortiert Queue-Einträge neu.
|
||||
|
||||
```json
|
||||
{
|
||||
"orderedJobIds": [42, 43, 41]
|
||||
"orderedEntryIds": [12, 11]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "queue": { ... } }`
|
||||
Legacy fallback wird akzeptiert:
|
||||
|
||||
```json
|
||||
{
|
||||
"orderedJobIds": [42, 43]
|
||||
}
|
||||
```
|
||||
|
||||
### POST /api/pipeline/queue/entry
|
||||
|
||||
Fügt Nicht-Job-Queue-Eintrag hinzu (`script`, `chain`, `wait`).
|
||||
|
||||
**Request-Beispiele:**
|
||||
|
||||
```json
|
||||
{ "type": "script", "scriptId": 3 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "type": "chain", "chainId": 2, "insertAfterEntryId": 11 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "type": "wait", "waitSeconds": 45 }
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": { "entryId": 12, "type": "wait", "position": 2 },
|
||||
"queue": { "...": "..." }
|
||||
}
|
||||
```
|
||||
|
||||
### DELETE /api/pipeline/queue/entry/:entryId
|
||||
|
||||
Entfernt Queue-Eintrag.
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "queue": { "...": "..." } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pipeline-Zustände
|
||||
|
||||
| State | Bedeutung |
|
||||
|------|-----------|
|
||||
| `IDLE` | Wartet auf Medium |
|
||||
| `DISC_DETECTED` | Medium erkannt |
|
||||
| `ANALYZING` | MakeMKV-Analyse läuft |
|
||||
| `METADATA_SELECTION` | Metadaten-Auswahl |
|
||||
| `WAITING_FOR_USER_DECISION` | Playlist-Entscheidung erforderlich |
|
||||
| `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 |
|
||||
| `FINISHED` | Abgeschlossen |
|
||||
| `CANCELLED` | Abgebrochen |
|
||||
| `ERROR` | Fehler |
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
# Settings API
|
||||
|
||||
Endpunkte zum Lesen und Schreiben der Anwendungseinstellungen.
|
||||
Endpunkte für Einstellungen, Skripte, Skript-Ketten und User-Presets.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/settings
|
||||
|
||||
Gibt alle Einstellungen kategorisiert zurück.
|
||||
Liefert alle Einstellungen kategorisiert.
|
||||
|
||||
**Response:**
|
||||
**Response (Struktur):**
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": {
|
||||
"raw_dir": {
|
||||
"value": "/mnt/nas/raw",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"label": "Raw-Verzeichnis",
|
||||
"description": "Speicherort für rohe MKV-Dateien",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"movie_dir": {
|
||||
"value": "/mnt/nas/movies",
|
||||
"schema": { ... }
|
||||
"categories": [
|
||||
{
|
||||
"category": "Pfade",
|
||||
"settings": [
|
||||
{
|
||||
"key": "raw_dir",
|
||||
"label": "Raw Ausgabeordner",
|
||||
"type": "path",
|
||||
"required": true,
|
||||
"description": "...",
|
||||
"defaultValue": "data/output/raw",
|
||||
"options": [],
|
||||
"validation": { "minLength": 1 },
|
||||
"value": "data/output/raw",
|
||||
"orderIndex": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"tools": { ... },
|
||||
"encoding": { ... },
|
||||
"drive": { ... },
|
||||
"makemkv": { ... },
|
||||
"omdb": { ... },
|
||||
"notifications": { ... }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -42,42 +40,44 @@ Gibt alle Einstellungen kategorisiert zurück.
|
||||
|
||||
Aktualisiert eine einzelne Einstellung.
|
||||
|
||||
**URL-Parameter:** `key` – Einstellungs-Schlüssel
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"value": "/mnt/storage/raw"
|
||||
}
|
||||
{ "value": "/mnt/storage/raw" }
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "ok": true, "key": "raw_dir", "value": "/mnt/storage/raw" }
|
||||
{
|
||||
"setting": {
|
||||
"key": "raw_dir",
|
||||
"value": "/mnt/storage/raw"
|
||||
},
|
||||
"reviewRefresh": {
|
||||
"triggered": false,
|
||||
"reason": "not_ready"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Fehlerfälle:**
|
||||
- `400` – Ungültiger Wert (Validierungsfehler)
|
||||
- `404` – Einstellung nicht gefunden
|
||||
|
||||
!!! note "Encode-Review-Refresh"
|
||||
Wenn eine encoding-relevante Einstellung geändert wird (z.B. `handbrake_preset`), wird der Encode-Plan für den aktuell wartenden Job automatisch neu berechnet.
|
||||
`reviewRefresh` ist `null` oder ein Objekt mit Status der optionalen Review-Neuberechnung.
|
||||
|
||||
---
|
||||
|
||||
## PUT /api/settings
|
||||
|
||||
Aktualisiert mehrere Einstellungen auf einmal.
|
||||
Aktualisiert mehrere Einstellungen atomar.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"raw_dir": "/mnt/storage/raw",
|
||||
"movie_dir": "/mnt/storage/movies",
|
||||
"handbrake_preset": "H.265 MKV 720p30"
|
||||
"settings": {
|
||||
"raw_dir": "/mnt/storage/raw",
|
||||
"movie_dir": "/mnt/storage/movies",
|
||||
"handbrake_preset_bluray": "H.264 MKV 1080p30"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -85,9 +85,36 @@ Aktualisiert mehrere Einstellungen auf einmal.
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"updated": ["raw_dir", "movie_dir", "handbrake_preset"],
|
||||
"errors": []
|
||||
"changes": [
|
||||
{ "key": "raw_dir", "value": "/mnt/storage/raw" },
|
||||
{ "key": "movie_dir", "value": "/mnt/storage/movies" }
|
||||
],
|
||||
"reviewRefresh": {
|
||||
"triggered": true,
|
||||
"jobId": 42,
|
||||
"relevantKeys": ["handbrake_preset_bluray"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bei Validierungsfehlern kommt `400` mit `error.details[]`.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/settings/handbrake-presets
|
||||
|
||||
Liest Preset-Liste via `HandBrakeCLI -z` (mit Fallback auf konfigurierte Presets).
|
||||
|
||||
**Response (Beispiel):**
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "handbrake-cli",
|
||||
"message": null,
|
||||
"options": [
|
||||
{ "label": "General/", "value": "__group__general", "disabled": true, "category": "General" },
|
||||
{ "label": " Fast 1080p30", "value": "Fast 1080p30", "category": "General" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -95,260 +122,217 @@ Aktualisiert mehrere Einstellungen auf einmal.
|
||||
|
||||
## POST /api/settings/pushover/test
|
||||
|
||||
Sendet eine Test-Benachrichtigung über PushOver.
|
||||
Sendet Testnachricht über aktuelle PushOver-Settings.
|
||||
|
||||
**Request:** Kein Body erforderlich (verwendet gespeicherte Zugangsdaten)
|
||||
|
||||
**Response (Erfolg):**
|
||||
|
||||
```json
|
||||
{ "ok": true, "message": "Test-Benachrichtigung gesendet" }
|
||||
```
|
||||
|
||||
**Response (Fehler):**
|
||||
|
||||
```json
|
||||
{ "ok": false, "error": "Ungültiger API-Token" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Skript-Verwaltung
|
||||
|
||||
Skripte werden über eigene Endpunkte unter `/api/settings/scripts` verwaltet. Jedes Skript hat eine `scriptBody`-Property (der Shell-Befehl oder mehrzeiliges Skript) und einen `orderIndex` für die Sortierung.
|
||||
|
||||
### GET /api/settings/scripts
|
||||
|
||||
Gibt alle Skripte zurück, sortiert nach `orderIndex`.
|
||||
|
||||
**Response:**
|
||||
**Request (optional):**
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Zu Plex verschieben",
|
||||
"scriptBody": "mv \"$RIPSTER_OUTPUT_PATH\" /mnt/plex/movies/",
|
||||
"orderIndex": 1,
|
||||
"createdAt": "2026-01-15T10:00:00.000Z",
|
||||
"updatedAt": "2026-01-15T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
"title": "Test",
|
||||
"message": "Ripster Test"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/settings/scripts
|
||||
|
||||
Legt ein neues Skript an.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Zu Plex verschieben",
|
||||
"scriptBody": "mv \"$RIPSTER_OUTPUT_PATH\" /mnt/plex/movies/"
|
||||
}
|
||||
```
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|------|-----|---------|-------------|
|
||||
| `name` | string | ✅ | Anzeigename (eindeutig) |
|
||||
| `scriptBody` | string | ✅ | Shell-Befehl oder mehrzeiliges Skript |
|
||||
|
||||
**Response:** `201 Created` – `{ "script": { ... } }`
|
||||
|
||||
---
|
||||
|
||||
### PUT /api/settings/scripts/:id
|
||||
|
||||
Aktualisiert ein vorhandenes Skript. Alle Felder optional.
|
||||
|
||||
---
|
||||
|
||||
### DELETE /api/settings/scripts/:id
|
||||
|
||||
Löscht ein Skript.
|
||||
|
||||
!!! warning "Referenzen"
|
||||
Das Skript wird gelöscht, auch wenn es in Job-Historien referenziert ist. In zukünftigen Reviews erscheint es nicht mehr.
|
||||
|
||||
---
|
||||
|
||||
### POST /api/settings/scripts/:id/test
|
||||
|
||||
Führt ein Skript mit Platzhalter-Umgebungsvariablen aus (Testlauf).
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"exitCode": 0,
|
||||
"stdout": "Testausgabe des Skripts",
|
||||
"stderr": "",
|
||||
"durationMs": 245
|
||||
}
|
||||
```
|
||||
|
||||
**Platzhalter-Werte beim Testlauf:**
|
||||
|
||||
| Variable | Testwert |
|
||||
|---------|---------|
|
||||
| `RIPSTER_OUTPUT_PATH` | `/tmp/ripster-test-output.mkv` |
|
||||
| `RIPSTER_JOB_ID` | `0` |
|
||||
| `RIPSTER_TITLE` | `Test Film` |
|
||||
| `RIPSTER_YEAR` | `2024` |
|
||||
| `RIPSTER_IMDB_ID` | `tt0000000` |
|
||||
| `RIPSTER_RAW_PATH` | `/tmp/ripster-test-raw.mkv` |
|
||||
|
||||
---
|
||||
|
||||
### POST /api/settings/scripts/reorder
|
||||
|
||||
Ändert die Reihenfolge der Skripte (persistiert in `order_index`).
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{ "orderedScriptIds": [3, 1, 2] }
|
||||
```
|
||||
|
||||
**Response:** `{ "scripts": [ ... ] }` – alle Skripte in neuer Reihenfolge.
|
||||
|
||||
---
|
||||
|
||||
## Skript-Ketten-Verwaltung
|
||||
|
||||
Skript-Ketten werden unter `/api/settings/script-chains` verwaltet.
|
||||
|
||||
### GET /api/settings/script-chains
|
||||
|
||||
Gibt alle Ketten zurück (inkl. Schritte).
|
||||
|
||||
### POST /api/settings/script-chains
|
||||
|
||||
Legt eine neue Kette an.
|
||||
|
||||
```json
|
||||
{ "name": "Nach Jellyfin deployen" }
|
||||
```
|
||||
|
||||
### PUT /api/settings/script-chains/:id
|
||||
|
||||
Aktualisiert eine Kette (Name, Schritte).
|
||||
|
||||
### DELETE /api/settings/script-chains/:id
|
||||
|
||||
Löscht eine Kette und alle ihre Schritte.
|
||||
|
||||
### POST /api/settings/script-chains/:id/test
|
||||
|
||||
Führt eine Kette mit Platzhalter-Umgebungsvariablen aus (Testlauf).
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"success": true,
|
||||
"steps": [
|
||||
{ "scriptId": 1, "scriptName": "Zu Plex verschieben", "success": true, "exitCode": 0 }
|
||||
]
|
||||
"sent": true,
|
||||
"eventKey": "test",
|
||||
"requestId": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Wenn PushOver deaktiviert ist oder Credentials fehlen, kommt i. d. R. ebenfalls `200` mit `sent: false` + `reason`.
|
||||
|
||||
---
|
||||
|
||||
## Skripte
|
||||
|
||||
Basis: `/api/settings/scripts`
|
||||
|
||||
### GET /api/settings/scripts
|
||||
|
||||
```json
|
||||
{ "scripts": [ { "id": 1, "name": "...", "scriptBody": "...", "orderIndex": 1, "createdAt": "...", "updatedAt": "..." } ] }
|
||||
```
|
||||
|
||||
### POST /api/settings/scripts
|
||||
|
||||
```json
|
||||
{ "name": "Move", "scriptBody": "mv \"$RIPSTER_OUTPUT_PATH\" /mnt/movies/" }
|
||||
```
|
||||
|
||||
Response: `201` mit `{ "script": { ... } }`
|
||||
|
||||
### PUT /api/settings/scripts/:id
|
||||
|
||||
Body wie `POST`, Response `{ "script": { ... } }`.
|
||||
|
||||
### DELETE /api/settings/scripts/:id
|
||||
|
||||
Response `{ "removed": { ... } }`.
|
||||
|
||||
### POST /api/settings/scripts/reorder
|
||||
|
||||
```json
|
||||
{ "orderedScriptIds": [3, 1, 2] }
|
||||
```
|
||||
|
||||
Response `{ "scripts": [ ... ] }`.
|
||||
|
||||
### POST /api/settings/scripts/:id/test
|
||||
|
||||
Führt Skript als Testlauf aus.
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"scriptId": 1,
|
||||
"scriptName": "Move",
|
||||
"success": true,
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"timedOut": false,
|
||||
"durationMs": 120,
|
||||
"stdout": "...",
|
||||
"stderr": "...",
|
||||
"stdoutTruncated": false,
|
||||
"stderrTruncated": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Umgebungsvariablen für Skripte
|
||||
|
||||
Diese Variablen werden beim Ausführen gesetzt:
|
||||
|
||||
- `RIPSTER_SCRIPT_RUN_AT`
|
||||
- `RIPSTER_JOB_ID`
|
||||
- `RIPSTER_JOB_TITLE`
|
||||
- `RIPSTER_MODE`
|
||||
- `RIPSTER_INPUT_PATH`
|
||||
- `RIPSTER_OUTPUT_PATH`
|
||||
- `RIPSTER_RAW_PATH`
|
||||
- `RIPSTER_SCRIPT_ID`
|
||||
- `RIPSTER_SCRIPT_NAME`
|
||||
- `RIPSTER_SCRIPT_SOURCE`
|
||||
|
||||
---
|
||||
|
||||
## Skript-Ketten
|
||||
|
||||
Basis: `/api/settings/script-chains`
|
||||
|
||||
Eine Kette hat Schritte vom Typ:
|
||||
|
||||
- `script` (`scriptId` erforderlich)
|
||||
- `wait` (`waitSeconds` 1..3600)
|
||||
|
||||
### GET /api/settings/script-chains
|
||||
|
||||
Response `{ "chains": [ ... ] }` (inkl. `steps[]`).
|
||||
|
||||
### GET /api/settings/script-chains/:id
|
||||
|
||||
Response `{ "chain": { ... } }`.
|
||||
|
||||
### POST /api/settings/script-chains
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "After Encode",
|
||||
"steps": [
|
||||
{ "stepType": "script", "scriptId": 1 },
|
||||
{ "stepType": "wait", "waitSeconds": 15 },
|
||||
{ "stepType": "script", "scriptId": 2 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Response: `201` mit `{ "chain": { ... } }`
|
||||
|
||||
### PUT /api/settings/script-chains/:id
|
||||
|
||||
Body wie `POST`, Response `{ "chain": { ... } }`.
|
||||
|
||||
### DELETE /api/settings/script-chains/:id
|
||||
|
||||
Response `{ "removed": { ... } }`.
|
||||
|
||||
### POST /api/settings/script-chains/reorder
|
||||
|
||||
Ändert die Reihenfolge der Ketten (persistiert in `order_index`).
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{ "orderedChainIds": [2, 1, 3] }
|
||||
```
|
||||
|
||||
Response `{ "chains": [ ... ] }`.
|
||||
|
||||
### POST /api/settings/script-chains/:id/test
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"chainId": 2,
|
||||
"chainName": "After Encode",
|
||||
"steps": 3,
|
||||
"succeeded": 3,
|
||||
"failed": 0,
|
||||
"aborted": false,
|
||||
"results": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User-Presets
|
||||
|
||||
Benannte HandBrake-Preset-Sammlungen, die im Encode-Review schnell angewendet werden können. Unter `/api/settings/user-presets` verwaltet.
|
||||
Basis: `/api/settings/user-presets`
|
||||
|
||||
### GET /api/settings/user-presets
|
||||
|
||||
Gibt alle User-Presets zurück. Optional gefiltert per Query-Parameter `mediaType`.
|
||||
|
||||
**Query-Parameter:**
|
||||
|
||||
| Parameter | Werte | Beschreibung |
|
||||
|-----------|-------|-------------|
|
||||
| `mediaType` | `bluray`, `dvd`, `other`, `all` | Filtert Presets nach Medientyp |
|
||||
|
||||
**Response:**
|
||||
Optionaler Query-Parameter: `media_type=bluray|dvd|other|all`
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Blu-ray High Quality",
|
||||
"name": "Blu-ray HQ",
|
||||
"mediaType": "bluray",
|
||||
"handbrakePreset": "H.265 MKV 1080p30",
|
||||
"handbrakePreset": "H.264 MKV 1080p30",
|
||||
"extraArgs": "--encoder-preset slow",
|
||||
"description": "Langsam, aber beste Qualität",
|
||||
"createdAt": "2026-01-15T10:00:00.000Z",
|
||||
"updatedAt": "2026-01-15T10:00:00.000Z"
|
||||
"description": "...",
|
||||
"createdAt": "...",
|
||||
"updatedAt": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/settings/user-presets
|
||||
|
||||
Legt ein neues User-Preset an.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Blu-ray High Quality",
|
||||
"name": "Blu-ray HQ",
|
||||
"mediaType": "bluray",
|
||||
"handbrakePreset": "H.265 MKV 1080p30",
|
||||
"handbrakePreset": "H.264 MKV 1080p30",
|
||||
"extraArgs": "--encoder-preset slow",
|
||||
"description": "Langsam, aber beste Qualität"
|
||||
"description": "optional"
|
||||
}
|
||||
```
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|------|-----|---------|-------------|
|
||||
| `name` | string | ✅ | Anzeigename |
|
||||
| `mediaType` | string | — | `bluray`, `dvd`, `other`, `all` (Standard: `all`) |
|
||||
| `handbrakePreset` | string | — | HandBrake-Preset-Name (`-Z`) |
|
||||
| `extraArgs` | string | — | Zusatz-CLI-Argumente |
|
||||
| `description` | string | — | Optionale Beschreibung |
|
||||
|
||||
**Response:** `201 Created` – `{ "preset": { ... } }`
|
||||
|
||||
---
|
||||
Response: `201` mit `{ "preset": { ... } }`
|
||||
|
||||
### PUT /api/settings/user-presets/:id
|
||||
|
||||
Aktualisiert ein User-Preset. Alle Felder optional.
|
||||
|
||||
---
|
||||
Body mit beliebigen Feldern aus `POST`, Response `{ "preset": { ... } }`.
|
||||
|
||||
### DELETE /api/settings/user-presets/:id
|
||||
|
||||
Löscht ein User-Preset.
|
||||
|
||||
---
|
||||
|
||||
## Einstellungs-Schlüssel Referenz
|
||||
|
||||
Eine vollständige Übersicht aller Schlüssel:
|
||||
[:octicons-arrow-right-24: Einstellungsreferenz](../configuration/settings-reference.md)
|
||||
Response `{ "removed": { ... } }`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# WebSocket Events
|
||||
|
||||
Ripster sendet Echtzeit-Updates über WebSocket unter `/ws`.
|
||||
Ripster sendet Echtzeit-Updates über `/ws`.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,8 +10,8 @@ Ripster sendet Echtzeit-Updates über WebSocket unter `/ws`.
|
||||
const ws = new WebSocket('ws://localhost:3001/ws');
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const message = JSON.parse(event.data);
|
||||
console.log(message.type, message.payload);
|
||||
const msg = JSON.parse(event.data);
|
||||
console.log(msg.type, msg.payload);
|
||||
};
|
||||
```
|
||||
|
||||
@@ -19,36 +19,38 @@ ws.onmessage = (event) => {
|
||||
|
||||
## Nachrichtenformat
|
||||
|
||||
Alle Broadcasts haben dieses Schema:
|
||||
Die meisten Broadcasts haben dieses Schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "EVENT_TYPE",
|
||||
"payload": { },
|
||||
"timestamp": "2026-03-05T10:00:00.000Z"
|
||||
"payload": {},
|
||||
"timestamp": "2026-03-10T09:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
Ausnahme: `WS_CONNECTED` beim Verbindungsaufbau enthält kein `timestamp`.
|
||||
|
||||
---
|
||||
|
||||
## Event-Typen
|
||||
|
||||
### WS_CONNECTED
|
||||
|
||||
Wird direkt nach Verbindungsaufbau gesendet.
|
||||
Sofort nach erfolgreicher Verbindung.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "WS_CONNECTED",
|
||||
"payload": {
|
||||
"connectedAt": "2026-03-05T10:00:00.000Z"
|
||||
"connectedAt": "2026-03-10T09:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PIPELINE_STATE_CHANGED
|
||||
|
||||
Snapshot bei Zustandswechsel.
|
||||
Neuer Pipeline-Snapshot.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -56,14 +58,24 @@ Snapshot bei Zustandswechsel.
|
||||
"payload": {
|
||||
"state": "ENCODING",
|
||||
"activeJobId": 42,
|
||||
"progress": 73.5,
|
||||
"progress": 62.5,
|
||||
"eta": "00:12:34",
|
||||
"statusText": "Encoding mit HandBrake",
|
||||
"statusText": "ENCODING 62.50%",
|
||||
"context": {},
|
||||
"jobProgress": {
|
||||
"42": {
|
||||
"state": "ENCODING",
|
||||
"progress": 62.5,
|
||||
"eta": "00:12:34",
|
||||
"statusText": "ENCODING 62.50%"
|
||||
}
|
||||
},
|
||||
"queue": {
|
||||
"maxParallelJobs": 1,
|
||||
"runningCount": 1,
|
||||
"queuedCount": 0
|
||||
"queuedCount": 2,
|
||||
"runningJobs": [],
|
||||
"queuedJobs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +83,7 @@ Snapshot bei Zustandswechsel.
|
||||
|
||||
### PIPELINE_PROGRESS
|
||||
|
||||
Laufende Fortschrittsupdates während aktiver Phasen.
|
||||
Laufende Fortschrittsupdates.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -79,33 +91,20 @@ Laufende Fortschrittsupdates während aktiver Phasen.
|
||||
"payload": {
|
||||
"state": "ENCODING",
|
||||
"activeJobId": 42,
|
||||
"progress": 73.5,
|
||||
"progress": 62.5,
|
||||
"eta": "00:12:34",
|
||||
"statusText": "ENCODING 73.50% - task 1 of 1"
|
||||
"statusText": "ENCODING 62.50%"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PIPELINE_QUEUE_CHANGED
|
||||
|
||||
Aktualisierung der Job-Queue.
|
||||
Queue-Snapshot aktualisiert.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "PIPELINE_QUEUE_CHANGED",
|
||||
"payload": {
|
||||
"maxParallelJobs": 1,
|
||||
"runningCount": 1,
|
||||
"queuedCount": 2,
|
||||
"runningJobs": [],
|
||||
"queuedJobs": []
|
||||
}
|
||||
}
|
||||
```
|
||||
### DISC_DETECTED / DISC_REMOVED
|
||||
|
||||
### DISC_DETECTED
|
||||
|
||||
Disc erkannt.
|
||||
Disc-Insertion/-Removal.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -114,7 +113,6 @@ Disc erkannt.
|
||||
"device": {
|
||||
"path": "/dev/sr0",
|
||||
"discLabel": "INCEPTION",
|
||||
"label": "INCEPTION",
|
||||
"model": "ASUS BW-16D1HT",
|
||||
"fstype": "udf",
|
||||
"mountpoint": null,
|
||||
@@ -124,132 +122,93 @@ Disc erkannt.
|
||||
}
|
||||
```
|
||||
|
||||
`mediaProfile` ist `"bluray"`, `"dvd"`, `"other"` oder `null` (wenn nicht bestimmbar). Der Wert wird aus Dateisystemtyp (UDF/ISO9660), Laufwerk-Modell und Disc-Label abgeleitet.
|
||||
`mediaProfile`: `bluray` | `dvd` | `other` | `null`
|
||||
|
||||
### DISC_REMOVED
|
||||
### HARDWARE_MONITOR_UPDATE
|
||||
|
||||
Disc entfernt.
|
||||
Snapshot aus Hardware-Monitoring.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "DISC_REMOVED",
|
||||
"type": "HARDWARE_MONITOR_UPDATE",
|
||||
"payload": {
|
||||
"device": {
|
||||
"path": "/dev/sr0"
|
||||
}
|
||||
"enabled": true,
|
||||
"intervalMs": 5000,
|
||||
"updatedAt": "2026-03-10T09:00:00.000Z",
|
||||
"sample": {
|
||||
"cpu": {},
|
||||
"memory": {},
|
||||
"gpu": {},
|
||||
"storage": {}
|
||||
},
|
||||
"error": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PIPELINE_ERROR
|
||||
|
||||
Fehler bei Pipeline-Disc-Events im Backend.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "PIPELINE_ERROR",
|
||||
"payload": {
|
||||
"message": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
Fehler bei Disc-Event-Verarbeitung in Pipeline.
|
||||
|
||||
### DISK_DETECTION_ERROR
|
||||
|
||||
Fehler im Laufwerkserkennungsdienst.
|
||||
Fehler in Laufwerkserkennung.
|
||||
|
||||
### SETTINGS_UPDATED
|
||||
|
||||
Einzelnes Setting wurde gespeichert.
|
||||
|
||||
### SETTINGS_BULK_UPDATED
|
||||
|
||||
Bulk-Settings gespeichert.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "DISK_DETECTION_ERROR",
|
||||
"type": "SETTINGS_BULK_UPDATED",
|
||||
"payload": {
|
||||
"message": "..."
|
||||
"count": 3,
|
||||
"keys": ["raw_dir", "movie_dir", "handbrake_preset_bluray"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SETTINGS_SCRIPTS_UPDATED
|
||||
|
||||
Wird gesendet, wenn ein Skript angelegt, aktualisiert, gelöscht oder umsortiert wurde.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "SETTINGS_SCRIPTS_UPDATED",
|
||||
"payload": {
|
||||
"action": "reordered",
|
||||
"count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`action` ist `"created"`, `"updated"`, `"deleted"` oder `"reordered"`.
|
||||
Skript geändert (`created|updated|deleted|reordered`).
|
||||
|
||||
### SETTINGS_SCRIPT_CHAINS_UPDATED
|
||||
|
||||
Wird gesendet bei Änderungen an Skript-Ketten.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "SETTINGS_SCRIPT_CHAINS_UPDATED",
|
||||
"payload": {
|
||||
"action": "created",
|
||||
"id": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
Skript-Kette geändert (`created|updated|deleted|reordered`).
|
||||
|
||||
### USER_PRESETS_UPDATED
|
||||
|
||||
Wird gesendet, wenn ein User-Preset angelegt, aktualisiert oder gelöscht wurde.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "USER_PRESETS_UPDATED",
|
||||
"payload": {
|
||||
"action": "created",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`action` ist `"created"`, `"updated"` oder `"deleted"`.
|
||||
User-Preset geändert (`created|updated|deleted`).
|
||||
|
||||
### CRON_JOBS_UPDATED
|
||||
|
||||
Wird gesendet, wenn ein Cron-Job angelegt, aktualisiert oder gelöscht wurde.
|
||||
Cron-Config geändert (`created|updated|deleted`).
|
||||
|
||||
### CRON_JOB_UPDATED
|
||||
|
||||
Laufzeitstatus eines Cron-Jobs geändert.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "CRON_JOBS_UPDATED",
|
||||
"type": "CRON_JOB_UPDATED",
|
||||
"payload": {
|
||||
"action": "created",
|
||||
"id": 1
|
||||
"id": 1,
|
||||
"lastRunStatus": "running",
|
||||
"lastRunAt": "2026-03-10T10:00:00.000Z",
|
||||
"nextRunAt": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`action` ist `"created"`, `"updated"` oder `"deleted"`.
|
||||
|
||||
---
|
||||
|
||||
## Reconnect-Verhalten
|
||||
|
||||
`useWebSocket.js` versucht bei Verbindungsabbruch automatisch erneut zu verbinden.
|
||||
`useWebSocket` verbindet bei Abbruch automatisch neu:
|
||||
|
||||
- fester Retry-Intervall: `1500ms`
|
||||
- erneuter Versuch bis zum Unmount der Komponente
|
||||
|
||||
---
|
||||
|
||||
## React-Beispiel
|
||||
|
||||
```js
|
||||
import { useWebSocket } from './hooks/useWebSocket';
|
||||
|
||||
useWebSocket({
|
||||
onMessage: (msg) => {
|
||||
if (msg.type === 'PIPELINE_STATE_CHANGED') {
|
||||
setPipeline(msg.payload);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
- Retry-Intervall: `1500ms`
|
||||
- Wiederverbindung bis Komponente unmounted wird
|
||||
|
||||
Reference in New Issue
Block a user