diff --git a/README.md b/README.md index f77e5b5..63ceada 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,28 @@ Ripster ist eine lokale Web-Anwendung für halbautomatisches Disc-Ripping mit MakeMKV + HandBrake inklusive Metadaten-Auswahl, Titel-/Spurprüfung und Job-Historie. +--- + +> **Neu seit letztem Release** +> +> - **Cron-Job-System** – Skripte und Skript-Ketten zeitgesteuert ausführen; eigener Expression-Parser, Ausführungs-Logs, manuelle Auslösung, PushOver-Integration +> - **DVD-Erkennung verbessert** – robuste Media-Profil-Erkennung (Blu-ray / DVD / CD) aus UDF/ISO9660-Dateisystemtyp, Laufwerk-Modell und Disc-Label +> - **Pre-Encode-Ausführungen** – Skripte und Ketten können nun auch *vor* dem Encode-Schritt ausgeführt werden (zusätzlich zu Post-Encode) +> - **Sortierbare Skripte & Ketten** – Reihenfolge über Drag & Drop festlegen; wird persistent in der Datenbank gespeichert +> - **`rip_successful`-Flag in Jobs** – separates Feld zur Nachverfolgung ob der Rip-Schritt abgeschlossen wurde (unabhängig vom Encode-Status) + +--- + ## Was Ripster kann - Disc-Erkennung mit Pipeline-Status in Echtzeit (WebSocket) +- Robuste Erkennung von Blu-ray, DVD und CD (UDF/ISO9660-Heuristik + Laufwerk-Modell) - Metadaten-Suche und Zuordnung über OMDb - MakeMKV-Analyse und Rip (MKV oder Backup-Modus) - HandBrake-Encode mit Preset + Extra-Args + Track-Override - Manuelle Playlist-/Titel-Auswahl bei komplexen Blu-rays +- Pre- und Post-Encode-Skripte & Skript-Ketten (inkl. Drag-and-Drop-Sortierung) +- Cron-Jobs: Skripte und Ketten zeitgesteuert ausführen (eigener Expression-Parser, Logs, PushOver) - Historie mit Re-Encode, Löschfunktionen und Detailansicht - Dateibasierte Logs (Backend + Job-Prozesslogs) @@ -138,15 +153,30 @@ ripster/ ## API-Überblick +**Pipeline** - `GET /api/pipeline/state` - `POST /api/pipeline/analyze` - `POST /api/pipeline/start/:jobId` - `POST /api/pipeline/confirm-encode/:jobId` + +**History** - `GET /api/history` - `GET /api/history/:id` + +**Settings** - `GET /api/settings` - `PUT /api/settings` +**Cron-Jobs** _(neu)_ +- `GET /api/crons` +- `POST /api/crons` +- `GET /api/crons/:id` +- `PUT /api/crons/:id` +- `DELETE /api/crons/:id` +- `GET /api/crons/:id/logs` +- `POST /api/crons/:id/run` +- `POST /api/crons/validate-expression` + ## Troubleshooting - WebSocket verbindet nicht: diff --git a/build-handbrake-nvdec.sh b/build-handbrake-nvdec.sh index 7aa54d0..dd8d520 100755 --- a/build-handbrake-nvdec.sh +++ b/build-handbrake-nvdec.sh @@ -81,15 +81,23 @@ else fi # -------------------------------------------------------------------------- -# 3. Alte Installation entfernen +# 3. Alle vorhandenen HandBrake-Installationen entfernen # -------------------------------------------------------------------------- -if command -v HandBrakeCLI &>/dev/null; then - EXISTING=$(HandBrakeCLI --version 2>&1 | head -1) - warn "Entferne vorhandenes HandBrakeCLI: ${EXISTING}" - apt-get remove -y handbrake-cli 2>/dev/null || true - snap remove handbrake-cli 2>/dev/null || true - rm -f /usr/bin/HandBrakeCLI /usr/local/bin/HandBrakeCLI -fi +info "Entferne alle vorhandenen HandBrake-Installationen..." +apt-get remove -y handbrake-cli handbrake 2>/dev/null || true +snap remove handbrake-cli 2>/dev/null || true +rm -f /usr/bin/HandBrakeCLI \ + /usr/local/bin/HandBrakeCLI \ + /snap/bin/handbrake-cli \ + /snap/bin/HandBrakeCLI +while true; do + FOUND=$(command -v HandBrakeCLI 2>/dev/null || true) + [[ -z "$FOUND" ]] && break + warn "Entferne: $FOUND" + rm -f "$FOUND" +done +hash -r 2>/dev/null || true +ok "Alte HandBrake-Installation(en) entfernt" # -------------------------------------------------------------------------- # 4. Quellcode herunterladen diff --git a/docs/api/crons.md b/docs/api/crons.md new file mode 100644 index 0000000..e17a7be --- /dev/null +++ b/docs/api/crons.md @@ -0,0 +1,243 @@ +# 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. + +--- + +## Endpunkte + +### `GET /api/crons` + +Alle konfigurierten Cron-Jobs auflisten. + +**Antwort:** + +```json +{ + "jobs": [ + { + "id": 1, + "name": "Nachtlauf Backup", + "cronExpression": "0 2 * * *", + "sourceType": "script", + "sourceId": 3, + "enabled": true, + "pushoverEnabled": true, + "lastRunAt": "2026-03-09T02:00:00.000Z", + "lastRunStatus": "success", + "nextRunAt": "2026-03-10T02:00:00.000Z", + "createdAt": "2026-03-01T10:00:00.000Z", + "updatedAt": "2026-03-09T02:00:00.000Z" + } + ] +} +``` + +--- + +### `POST /api/crons` + +Neuen Cron-Job anlegen. + +**Body:** + +```json +{ + "name": "Nachtlauf Backup", + "cronExpression": "0 2 * * *", + "sourceType": "script", + "sourceId": 3, + "enabled": true, + "pushoverEnabled": true +} +``` + +| 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`) | + +**Antwort:** `201 Created` + +```json +{ "job": { ... } } +``` + +--- + +### `GET /api/crons/:id` + +Einzelnen Cron-Job abrufen. + +**Antwort:** + +```json +{ "job": { ... } } +``` + +--- + +### `PUT /api/crons/:id` + +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. + +**Query-Parameter:** + +| Parameter | Typ | Default | Beschreibung | +|-----------|-----|---------|-------------| +| `limit` | number | 20 | Anzahl Einträge (max. 100) | + +**Antwort:** + +```json +{ + "logs": [ + { + "id": 42, + "cronJobId": 1, + "startedAt": "2026-03-09T02:00:01.000Z", + "finishedAt": "2026-03-09T02:00:05.000Z", + "status": "success", + "exitCode": 0, + "stdout": "Backup abgeschlossen.", + "stderr": "", + "triggeredBy": "cron" + } + ] +} +``` + +| Feld | Beschreibung | +|------|-------------| +| `status` | `"success"`, `"error"` oder `"running"` | +| `triggeredBy` | `"cron"` (zeitgesteuert) oder `"manual"` (manuell ausgelöst) | + +--- + +### `POST /api/crons/:id/run` + +Cron-Job sofort manuell auslösen (unabhängig vom Zeitplan). + +**Antwort:** + +```json +{ + "status": "success", + "exitCode": 0, + "stdout": "...", + "stderr": "" +} +``` + +--- + +### `POST /api/crons/validate-expression` + +Cron-Ausdruck validieren und nächsten Ausführungszeitpunkt berechnen. + +**Body:** + +```json +{ "cronExpression": "*/15 * * * *" } +``` + +**Antwort (gültig):** + +```json +{ + "valid": true, + "nextRunAt": "2026-03-09T14:15:00.000Z" +} +``` + +**Antwort (ungültig):** + +```json +{ + "valid": false, + "error": "Cron-Ausdruck muss genau 5 Felder haben (Minute Stunde Tag Monat Wochentag).", + "nextRunAt": null +} +``` + +--- + +## Cron-Expression-Format + +Ripster verwendet **5-Felder-Cron-Ausdrücke** (kein Sekunden-Feld): + +``` +┌───────────── Minute (0-59) +│ ┌────────── Stunde (0-23) +│ │ ┌─────── Tag (1-31) +│ │ │ ┌──── Monat (1-12) +│ │ │ │ ┌─ Wochentag (0-7, 0 und 7 = Sonntag) +│ │ │ │ │ +* * * * * +``` + +### 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` | + +--- + +## WebSocket-Event + +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"`. diff --git a/docs/api/index.md b/docs/api/index.md index 9027d85..c446edf 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -42,6 +42,14 @@ Konfigurierbar über die Umgebungsvariable `PORT`. [:octicons-arrow-right-24: History API](history.md) +- :material-clock-outline: **Cron API** + + --- + + Cron-Jobs verwalten, manuell auslösen und Ausführungs-Logs abrufen. + + [:octicons-arrow-right-24: Cron API](crons.md) + - :material-lightning-bolt: **WebSocket Events** --- diff --git a/docs/api/websocket.md b/docs/api/websocket.md index 4daf488..714389f 100644 --- a/docs/api/websocket.md +++ b/docs/api/websocket.md @@ -113,12 +113,19 @@ Disc erkannt. "payload": { "device": { "path": "/dev/sr0", - "discLabel": "INCEPTION" + "discLabel": "INCEPTION", + "label": "INCEPTION", + "model": "ASUS BW-16D1HT", + "fstype": "udf", + "mountpoint": null, + "mediaProfile": "bluray" } } } ``` +`mediaProfile` ist `"bluray"`, `"dvd"`, `"other"` oder `null` (wenn nicht bestimmbar). Der Wert wird aus Dateisystemtyp (UDF/ISO9660), Laufwerk-Modell und Disc-Label abgeleitet. + ### DISC_REMOVED Disc entfernt. @@ -160,6 +167,22 @@ Fehler im Laufwerkserkennungsdienst. } ``` +### CRON_JOBS_UPDATED + +Wird gesendet, wenn ein Cron-Job angelegt, aktualisiert oder gelöscht wurde. + +```json +{ + "type": "CRON_JOBS_UPDATED", + "payload": { + "action": "created", + "id": 1 + } +} +``` + +`action` ist `"created"`, `"updated"` oder `"deleted"`. + --- ## Reconnect-Verhalten diff --git a/docs/architecture/database.md b/docs/architecture/database.md index 523391b..9bc4afb 100644 --- a/docs/architecture/database.md +++ b/docs/architecture/database.md @@ -7,11 +7,15 @@ Ripster verwendet **SQLite3** als Datenbank. Die Datenbankdatei liegt unter `bac ## Schema-Übersicht ```sql --- Vier Haupt-Tabellen settings_schema -- Einstellungs-Definitionen settings_values -- Benutzer-Werte jobs -- Rip-Job-Datensätze pipeline_state -- Aktueller Pipeline-Zustand (Singleton) +scripts -- Shell-Skripte für Pre-/Post-Encode-Ausführung +script_chains -- Geordnete Ketten aus mehreren Skripten +script_chain_steps -- Einzelschritte einer Skript-Kette +cron_jobs -- Zeitgesteuerte Aufgaben (eigener Cron-Parser) +cron_run_logs -- Ausführungs-Protokolle für Cron-Jobs ``` --- @@ -22,27 +26,31 @@ Die wichtigste Tabelle – speichert alle Ripping-Jobs. ```sql CREATE TABLE jobs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - created_at TEXT NOT NULL, - updated_at TEXT NOT NULL, - status TEXT NOT NULL, -- Aktueller Status - title TEXT, -- Filmtitel (von OMDb) - imdb_id TEXT, -- IMDb-ID - omdb_year TEXT, -- Erscheinungsjahr - omdb_type TEXT, -- movie/series - omdb_poster TEXT, -- Poster-URL - raw_path TEXT, -- Pfad zur Raw-MKV - output_path TEXT, -- Pfad zur Ausgabedatei - playlist TEXT, -- Gewählte Blu-ray Playlist - makemkv_output TEXT, -- MakeMKV-Ausgabe (JSON) - mediainfo_output TEXT, -- MediaInfo-Ausgabe (JSON) - encode_plan TEXT, -- Encode-Plan (JSON) - handbrake_log TEXT, -- HandBrake Log-Pfad - error_message TEXT, -- Fehlermeldung bei ERROR - error_details TEXT -- Detaillierte Fehler-Infos + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + status TEXT NOT NULL, -- Aktueller Status + title TEXT, -- Filmtitel (von OMDb) + imdb_id TEXT, -- IMDb-ID + omdb_year TEXT, -- Erscheinungsjahr + omdb_type TEXT, -- movie/series + omdb_poster TEXT, -- Poster-URL + raw_path TEXT, -- Pfad zur Raw-MKV + output_path TEXT, -- Pfad zur Ausgabedatei + playlist TEXT, -- Gewählte Blu-ray Playlist + rip_successful INTEGER NOT NULL DEFAULT 0, -- 1 wenn Rip abgeschlossen + makemkv_output TEXT, -- MakeMKV-Ausgabe (JSON) + mediainfo_output TEXT, -- MediaInfo-Ausgabe (JSON) + encode_plan TEXT, -- Encode-Plan (JSON) + handbrake_log TEXT, -- HandBrake Log-Pfad + error_message TEXT, -- Fehlermeldung bei ERROR + error_details TEXT -- Detaillierte Fehler-Infos ); ``` +!!! info "rip_successful" + Das Feld `rip_successful` wird auf `1` gesetzt, sobald MakeMKV den Rip-Schritt erfolgreich abgeschlossen hat – unabhängig davon, ob danach ein Encode-Fehler auftritt. Damit lässt sich in der History unterscheiden, ob eine Raw-Datei vorhanden ist. + ### Job-Status-Werte | Status | Beschreibung | @@ -111,6 +119,87 @@ CREATE TABLE settings_values ( --- +## Tabelle: scripts + +Verwaltet Shell-Skripte, die vor oder nach dem Encode-Schritt ausgeführt werden können. + +```sql +CREATE TABLE scripts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE, + script_body TEXT NOT NULL, + order_index INTEGER NOT NULL DEFAULT 0, -- Sortierposition in der UI + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); +``` + +## Tabelle: script_chains + +Geordnete Ketten, die mehrere Skripte sequenziell zusammenfassen. + +```sql +CREATE TABLE script_chains ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE, + order_index INTEGER NOT NULL DEFAULT 0, -- Sortierposition in der UI + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE script_chain_steps ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + chain_id INTEGER NOT NULL REFERENCES script_chains(id) ON DELETE CASCADE, + script_id INTEGER NOT NULL REFERENCES scripts(id) ON DELETE CASCADE, + step_order INTEGER NOT NULL DEFAULT 0, + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); +``` + +!!! info "Sortierung" + `order_index` in `scripts` und `script_chains` wird über die API (`reorderScripts` / `reorderChains`) per Drag & Drop in der UI gesetzt und bleibt persistent gespeichert. + +--- + +## Tabellen: cron_jobs & cron_run_logs + +Speichern den Zeitplan und die Ausführungs-Historie des eingebauten Cron-Systems. + +```sql +CREATE TABLE cron_jobs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + cron_expression TEXT NOT NULL, -- 5-Felder-Ausdruck (min h d m wd) + source_type TEXT NOT NULL, -- "script" oder "chain" + source_id INTEGER NOT NULL, -- ID des Skripts/der Kette + enabled INTEGER NOT NULL DEFAULT 1, + pushover_enabled INTEGER NOT NULL DEFAULT 1, + last_run_at TEXT, + last_run_status TEXT, -- "success", "error", "running" + next_run_at TEXT, + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE cron_run_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + cron_job_id INTEGER NOT NULL REFERENCES cron_jobs(id) ON DELETE CASCADE, + started_at TEXT NOT NULL, + finished_at TEXT, + status TEXT NOT NULL, -- "success", "error", "running" + exit_code INTEGER, + stdout TEXT, + stderr TEXT, + triggered_by TEXT NOT NULL DEFAULT 'cron', -- "cron" oder "manual" + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); +``` + +!!! info "Log-Rotation" + Pro Cron-Job werden maximal **50 Log-Einträge** gespeichert; ältere Einträge werden automatisch gelöscht. Stdout/Stderr werden auf **100.000 Zeichen** begrenzt. + +--- + ## Schema-Migrationen `database.js` implementiert **automatische Migrationen**: @@ -126,7 +215,7 @@ Falls die Datenbankdatei korrupt ist: ``` 1. Korrupte Datei wird erkannt (Verbindungsfehler / Integritätsprüfung) -2. Datei wird in /backend/data/quarantine/ verschoben +2. Datei wird in backend/data/corrupt-backups/ verschoben 3. Neue, leere Datenbank wird erstellt 4. Schema wird neu initialisiert 5. Log-Eintrag mit Warnung diff --git a/docs/pipeline/post-encode-scripts.md b/docs/pipeline/post-encode-scripts.md index 77e80b6..5da7a67 100644 --- a/docs/pipeline/post-encode-scripts.md +++ b/docs/pipeline/post-encode-scripts.md @@ -1,34 +1,34 @@ -# Post-Encode-Skripte +# Encode-Skripte (Pre & Post) -Post-Encode-Skripte ermöglichen es, nach erfolgreichem Encoding automatisch beliebige Shell-Befehle oder Programme auszuführen – z. B. zum Verschieben von Dateien, Benachrichtigen externer Dienste oder Auslösen weiterer Verarbeitungsschritte. +Ripster unterstützt **Pre-Encode-** und **Post-Encode-Ausführungen**: Beliebige Shell-Skripte oder Skript-Ketten können automatisch vor und/oder nach dem Encoding-Schritt laufen – z. B. zum Vorbereiten von Verzeichnissen, Verschieben von Dateien oder Benachrichtigen externer Dienste. --- ## Funktionsweise -Nach einem erfolgreich abgeschlossenen Encoding-Schritt führt Ripster die konfigurierten Skripte **sequenziell** in der festgelegten Reihenfolge aus: - ``` -ENCODING abgeschlossen +READY_TO_ENCODE ↓ -Skript 1 ausführen ← Fehler? → Abbruch +[Pre-Encode-Ausführungen] ← Fehler? → Abbruch + Skript/Kette 1, 2, … ↓ -Skript 2 ausführen ← Fehler? → Abbruch +ENCODING ↓ - ... +[Post-Encode-Ausführungen] ← Fehler? → Abbruch + Skript/Kette 1, 2, … ↓ FINISHED ``` !!! warning "Abbruch bei Fehler" - Schlägt ein Skript fehl (Exit-Code ≠ 0), werden alle nachfolgenden Skripte **nicht mehr ausgeführt**. - Der Job bleibt im Abschlusszustand `FINISHED`; der Fehler wird in Log/Status-Text und im `postEncodeScripts`-Summary festgehalten. + Schlägt eine Ausführung fehl (Exit-Code ≠ 0), werden alle nachfolgenden Ausführungen der gleichen Phase **nicht mehr ausgeführt**. + Der Job bleibt im Abschlusszustand `FINISHED`; der Fehler wird in Log/Status-Text und im Summary festgehalten. --- -## Skript-Verwaltung +## Skript- und Ketten-Verwaltung -Skripte werden über die **Einstellungen-Seite** angelegt und verwaltet. Sie stehen danach in jedem Encode-Review zur Auswahl. +Skripte und Skript-Ketten werden über die **Einstellungen-Seite** angelegt und verwaltet. Die Reihenfolge in der Liste kann per **Drag & Drop** geändert werden und bleibt persistent gespeichert. ### Skript anlegen @@ -40,6 +40,10 @@ Navigiere zu **Einstellungen → Skripte** und klicke **"Neues Skript"**: | **Befehl** | Shell-Befehl oder Skriptpfad (z. B. `/home/michael/scripts/move-to-plex.sh`) | | **Beschreibung** | Optionale Erklärung | +### Skript-Ketten + +Eine **Skript-Kette** fasst mehrere Skripte zu einer benannten Einheit zusammen, die als ganzes ausgewählt werden kann. Nützlich für wiederkehrende Kombinationen (z. B. „Move + Notify Plex + Webhook"). Ketten werden genauso wie einzelne Skripte im Review-Panel ausgewählt. + ### Verfügbare Umgebungsvariablen Jedes Skript wird mit folgenden Umgebungsvariablen aufgerufen: @@ -78,26 +82,35 @@ curl -s -X POST https://mein-webhook.example.com/ripster \ --- -## Skript im Encode-Review auswählen +## Im Encode-Review auswählen -Im `READY_TO_ENCODE`-Zustand zeigt das **MediaInfoReviewPanel** einen Skript-Abschnitt: +Im `READY_TO_ENCODE`-Zustand zeigt das **MediaInfoReviewPanel** zwei Abschnitte: ``` ┌──────────────────────────────────────────────────────────┐ -│ Post-Encode-Skripte │ +│ Pre-Encode Ausführungen (optional) │ ├──────────────────────────────────────────────────────────┤ -│ Ausgewählte Skripte (Reihenfolge per Drag & Drop): │ -│ ≡ 1. Zu Plex verschieben [Entfernen]│ -│ ≡ 2. Webhook auslösen [Entfernen]│ +│ ≡ 1. Verzeichnis vorbereiten (Skript) [Entfernen]│ ├──────────────────────────────────────────────────────────┤ -│ Skript hinzufügen: [Zu Jellyfin verschieben ▾] [+ Hinzuf.]│ +│ Hinzufügen: [Skript/Kette auswählen ▾] [+ Hinzuf.]│ +└──────────────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────────────┐ +│ Post-Encode Ausführungen (optional) │ +├──────────────────────────────────────────────────────────┤ +│ ≡ 1. Zu Plex verschieben (Skript) [Entfernen]│ +│ ≡ 2. Notify-Kette (Kette) [Entfernen]│ +├──────────────────────────────────────────────────────────┤ +│ Hinzufügen: [Skript/Kette auswählen ▾] [+ Hinzuf.]│ └──────────────────────────────────────────────────────────┘ ``` -- **Reihenfolge** per Drag & Drop ändern -- **Hinzufügen** aus der Dropdown-Liste aller konfigurierten Skripte -- **Entfernen** einzelner Skripte aus der aktuellen Auswahl -- Skripte können pro Job unterschiedlich gewählt werden +- **Pre-Encode** und **Post-Encode** werden separat konfiguriert +- Sowohl **einzelne Skripte** als auch **Skript-Ketten** können in beiden Phasen ausgewählt werden +- **Reihenfolge** per Drag & Drop innerhalb jeder Phase ändern +- **Hinzufügen** aus der Dropdown-Liste aller konfigurierten Skripte und Ketten +- **Entfernen** einzelner Einträge +- Auswahl kann pro Job frei variiert werden --- diff --git a/install-dev.sh b/install-dev.sh index 8181ef5..0c524f0 100755 --- a/install-dev.sh +++ b/install-dev.sh @@ -183,6 +183,25 @@ install_makemkv() { warn "Beta-Key: https://www.makemkv.com/forum/viewtopic.php?t=1053" } +remove_all_handbrake() { + info "Entferne alle vorhandenen HandBrake-Installationen..." + apt-get remove -y handbrake-cli handbrake 2>/dev/null || true + snap remove handbrake-cli 2>/dev/null || true + rm -f /usr/bin/HandBrakeCLI \ + /usr/local/bin/HandBrakeCLI \ + /snap/bin/handbrake-cli \ + /snap/bin/HandBrakeCLI + while true; do + local found + found=$(command -v HandBrakeCLI 2>/dev/null || true) + [[ -z "$found" ]] && break + warn "Entferne: $found" + rm -f "$found" + done + hash -r 2>/dev/null || true + ok "Alte HandBrake-Installation(en) entfernt" +} + build_handbrake_nvdec() { header "HandBrake ${HANDBRAKE_VERSION} mit NVDEC aus Quellcode bauen" @@ -191,6 +210,9 @@ build_handbrake_nvdec() { local src_url="https://github.com/HandBrake/HandBrake/releases/download/${HANDBRAKE_VERSION}/HandBrake-${HANDBRAKE_VERSION}-source.tar.bz2" local tarball="${tmp_dir}/handbrake-src.tar.bz2" + # Alte Installationen vollständig entfernen + remove_all_handbrake + # Build-Abhängigkeiten info "Installiere Build-Abhängigkeiten..." apt-get install -y \ @@ -220,14 +242,6 @@ build_handbrake_nvdec() { fi ok "Build-Abhängigkeiten installiert" - # Alte Installation entfernen - if command_exists HandBrakeCLI; then - warn "Entferne vorhandenes HandBrakeCLI..." - apt-get remove -y handbrake-cli 2>/dev/null || true - snap remove handbrake-cli 2>/dev/null || true - rm -f /usr/bin/HandBrakeCLI /usr/local/bin/HandBrakeCLI - fi - # Quellcode herunterladen info "Lade HandBrake ${HANDBRAKE_VERSION} herunter..." curl -fsSL "$src_url" -o "$tarball" 2>/dev/null || \ diff --git a/install.sh b/install.sh index e7b971f..aa75b7f 100755 --- a/install.sh +++ b/install.sh @@ -188,6 +188,29 @@ install_makemkv() { warn "Beta-Key: https://www.makemkv.com/forum/viewtopic.php?t=1053" } +remove_all_handbrake() { + info "Entferne alle vorhandenen HandBrake-Installationen..." + # apt + apt-get remove -y handbrake-cli handbrake 2>/dev/null || true + # snap + snap remove handbrake-cli 2>/dev/null || true + # bekannte Binär-Pfade + rm -f /usr/bin/HandBrakeCLI \ + /usr/local/bin/HandBrakeCLI \ + /snap/bin/handbrake-cli \ + /snap/bin/HandBrakeCLI + # alle weiteren Fundstellen über PATH + while true; do + local found + found=$(command -v HandBrakeCLI 2>/dev/null || true) + [[ -z "$found" ]] && break + warn "Entferne: $found" + rm -f "$found" + done + hash -r 2>/dev/null || true + ok "Alte HandBrake-Installation(en) entfernt" +} + build_handbrake_nvdec() { header "HandBrake ${HANDBRAKE_VERSION} mit NVDEC aus Quellcode bauen" @@ -196,6 +219,9 @@ build_handbrake_nvdec() { local src_url="https://github.com/HandBrake/HandBrake/releases/download/${HANDBRAKE_VERSION}/HandBrake-${HANDBRAKE_VERSION}-source.tar.bz2" local tarball="${tmp_dir}/handbrake-src.tar.bz2" + # Alte Installationen vollständig entfernen + remove_all_handbrake + # Build-Abhängigkeiten info "Installiere Build-Abhängigkeiten..." apt-get install -y \ @@ -213,7 +239,6 @@ build_handbrake_nvdec() { if ! dpkg -l 2>/dev/null | grep -q '^ii.*nvidia-cuda-toolkit'; then apt-get install -y nvidia-cuda-toolkit >/dev/null 2>&1 || { warn "nvidia-cuda-toolkit nicht verfügbar – versuche Fallback-Header..." - # Fallback: nur die minimalen Header aus dem NVIDIA-CUDA-Repo local cuda_keyring="/tmp/cuda-keyring.deb" local ubuntu_ver="${VERSION_ID//./}" curl -fsSL "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${ubuntu_ver}/x86_64/cuda-keyring_1.1-1_all.deb" \ @@ -226,14 +251,6 @@ build_handbrake_nvdec() { fi ok "Build-Abhängigkeiten installiert" - # Alte Installation entfernen - if command_exists HandBrakeCLI; then - warn "Entferne vorhandenes HandBrakeCLI..." - apt-get remove -y handbrake-cli 2>/dev/null || true - snap remove handbrake-cli 2>/dev/null || true - rm -f /usr/bin/HandBrakeCLI /usr/local/bin/HandBrakeCLI - fi - # Quellcode herunterladen info "Lade HandBrake ${HANDBRAKE_VERSION} herunter..." curl -fsSL "$src_url" -o "$tarball" 2>/dev/null || \ diff --git a/mkdocs.yml b/mkdocs.yml index d4d9063..089778d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,12 +62,13 @@ nav: - Workflow & Zustände: pipeline/workflow.md - Encode-Planung & Track-Auswahl: pipeline/encoding.md - Playlist-Analyse: pipeline/playlist-analysis.md - - Post-Encode-Skripte: pipeline/post-encode-scripts.md + - Encode-Skripte (Pre & Post): pipeline/post-encode-scripts.md - API-Referenz: - api/index.md - Pipeline API: api/pipeline.md - Settings API: api/settings.md - History API: api/history.md + - Cron API: api/crons.md - WebSocket Events: api/websocket.md - Konfiguration: - configuration/index.md