{"config":{"lang":["de"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Ripster Handbuch","text":"
Dieses Dokumentationsset ist als Benutzerhandbuch aufgebaut: erst Bedienung und Alltag, dann Technik im Anhang.
"},{"location":"#schnellstart-in-3-schritten","title":"Schnellstart in 3 Schritten","text":"Dashboard, Settings, Historie, Database)REST- und WebSocket-Schnittstellen f\u00fcr Integration, Automatisierung und Debugging.
"},{"location":"api/#basis-url","title":"Basis-URL","text":"http://localhost:3001\n API-Prefix: /api
Health
Service-Liveness.
GET /api/health
Pipeline API
Analyse, Start/Retry/Cancel, Queue, Re-Encode.
Pipeline API
Settings API
Einstellungen, Skripte/Ketten, User-Presets.
Settings API
History API
Job-Historie, Orphan-Import, L\u00f6schoperationen.
History API
Cron API
Zeitgesteuerte Skript-/Kettenausf\u00fchrung.
Cron API
WebSocket Events
Pipeline-, Queue-, Disk-, Settings-, Cron- und Monitoring-Events.
WebSocket
Ripster hat keine eingebaute Authentifizierung und ist f\u00fcr lokalen, gesch\u00fctzten Betrieb gedacht.
"},{"location":"api/crons/","title":"Cron API","text":"Ripster enth\u00e4lt ein eingebautes Cron-System f\u00fcr Skripte und Skript-Ketten (sourceType: script|chain).
Listet alle Cron-Jobs.
{\n \"jobs\": [\n {\n \"id\": 1,\n \"name\": \"Nachtlauf Backup\",\n \"cronExpression\": \"0 2 * * *\",\n \"sourceType\": \"script\",\n \"sourceId\": 3,\n \"sourceName\": \"Backup-Skript\",\n \"enabled\": true,\n \"pushoverEnabled\": true,\n \"lastRunAt\": \"2026-03-10T02:00:00.000Z\",\n \"lastRunStatus\": \"success\",\n \"nextRunAt\": \"2026-03-11T02:00:00.000Z\",\n \"createdAt\": \"2026-03-01T10:00:00.000Z\",\n \"updatedAt\": \"2026-03-10T02:00:05.000Z\"\n }\n ]\n}\n"},{"location":"api/crons/#post-apicrons","title":"POST /api/crons","text":"Erstellt Cron-Job.
{\n \"name\": \"Nachtlauf Backup\",\n \"cronExpression\": \"0 2 * * *\",\n \"sourceType\": \"script\",\n \"sourceId\": 3,\n \"enabled\": true,\n \"pushoverEnabled\": true\n}\n Response: 201 mit { \"job\": { ... } }
Response:
{ \"job\": { \"id\": 1, \"name\": \"...\" } }\n"},{"location":"api/crons/#put-apicronsid","title":"PUT /api/crons/:id","text":"Aktualisiert Cron-Job. Felder wie bei POST.
Response:
{ \"job\": { ... } }\n"},{"location":"api/crons/#delete-apicronsid","title":"DELETE /api/crons/:id","text":"Response:
{ \"removed\": { \"id\": 1, \"name\": \"Nachtlauf Backup\" } }\n"},{"location":"api/crons/#get-apicronsidlogs","title":"GET /api/crons/:id/logs","text":"Liefert Ausf\u00fchrungs-Logs.
Query-Parameter:
Parameter Typ Default Beschreibunglimit number 20 Anzahl Eintr\u00e4ge, max. 100 Response:
{\n \"logs\": [\n {\n \"id\": 42,\n \"cronJobId\": 1,\n \"startedAt\": \"2026-03-10T02:00:01.000Z\",\n \"finishedAt\": \"2026-03-10T02:00:05.000Z\",\n \"status\": \"success\",\n \"output\": \"Backup abgeschlossen.\",\n \"errorMessage\": null\n }\n ]\n}\n status: running | success | error
Triggert Job manuell (asynchron).
Response:
{ \"triggered\": true, \"cronJobId\": 1 }\n Wenn Job bereits l\u00e4uft: 409.
Validiert 5-Felder-Cron-Ausdruck und berechnet n\u00e4chsten Lauf.
Request:
{ \"cronExpression\": \"*/15 * * * *\" }\n G\u00fcltige Response:
{\n \"valid\": true,\n \"nextRunAt\": \"2026-03-10T14:15:00.000Z\"\n}\n Ung\u00fcltige Response:
{\n \"valid\": false,\n \"error\": \"Cron-Ausdruck muss genau 5 Felder haben (Minute Stunde Tag Monat Wochentag).\",\n \"nextRunAt\": null\n}\n"},{"location":"api/crons/#cron-format","title":"Cron-Format","text":"Ripster unterst\u00fctzt 5 Felder:
Minute Stunde Tag Monat Wochentag\n Beispiele:
0 2 * * * t\u00e4glich 02:00*/15 * * * * alle 15 Minuten0 6 * * 1-5 Mo-Fr 06:00CRON_JOBS_UPDATED bei Create/Update/DeleteCRON_JOB_UPDATED bei Laufzeitstatus (running -> success|error)Endpunkte f\u00fcr Job-Historie, Orphan-Import und L\u00f6schoperationen.
"},{"location":"api/history/#get-apihistory","title":"GET /api/history","text":"Liefert Jobs (optionale Filter).
Query-Parameter:
Parameter Typ Beschreibungstatus string Filter nach Job-Status search string Suche in Titel-Feldern Beispiel:
GET /api/history?status=FINISHED&search=Inception\n Response:
{\n \"jobs\": [\n {\n \"id\": 42,\n \"status\": \"FINISHED\",\n \"title\": \"Inception\",\n \"raw_path\": \"/mnt/raw/Inception - RAW - job-42\",\n \"output_path\": \"/mnt/movies/Inception (2010)/Inception (2010).mkv\",\n \"mediaType\": \"bluray\",\n \"ripSuccessful\": true,\n \"encodeSuccess\": true,\n \"created_at\": \"2026-03-10T08:00:00.000Z\",\n \"updated_at\": \"2026-03-10T10:00:00.000Z\"\n }\n ]\n}\n"},{"location":"api/history/#get-apihistoryid","title":"GET /api/history/:id","text":"Liefert Job-Detail.
Query-Parameter:
Parameter Typ Standard BeschreibungincludeLogs bool false Prozesslog laden includeLiveLog bool false alias-artig ebenfalls Prozesslog laden includeAllLogs bool false vollst\u00e4ndiges Log statt Tail logTailLines number 800 Tail-L\u00e4nge falls nicht includeAllLogs Response:
{\n \"job\": {\n \"id\": 42,\n \"status\": \"FINISHED\",\n \"makemkvInfo\": {},\n \"mediainfoInfo\": {},\n \"handbrakeInfo\": {},\n \"encodePlan\": {},\n \"log\": \"...\",\n \"log_count\": 1,\n \"logMeta\": {\n \"loaded\": true,\n \"total\": 800,\n \"returned\": 800,\n \"truncated\": true\n }\n }\n}\n"},{"location":"api/history/#get-apihistorydatabase","title":"GET /api/history/database","text":"Debug-Ansicht der DB-Zeilen (angereichert).
Response:
{\n \"rows\": [\n {\n \"id\": 42,\n \"status\": \"FINISHED\",\n \"rawFolderName\": \"Inception - RAW - job-42\"\n }\n ]\n}\n"},{"location":"api/history/#get-apihistoryorphan-raw","title":"GET /api/history/orphan-raw","text":"Sucht RAW-Ordner ohne zugeh\u00f6rigen Job.
Response:
{\n \"rawDir\": \"/mnt/raw\",\n \"rawDirs\": [\"/mnt/raw\", \"/mnt/raw-bluray\"],\n \"rows\": [\n {\n \"rawPath\": \"/mnt/raw/Inception (2010) [tt1375666] - RAW - job-99\",\n \"folderName\": \"Inception (2010) [tt1375666] - RAW - job-99\",\n \"title\": \"Inception\",\n \"year\": 2010,\n \"imdbId\": \"tt1375666\",\n \"folderJobId\": 99,\n \"entryCount\": 4,\n \"hasBlurayStructure\": true,\n \"lastModifiedAt\": \"2026-03-10T09:00:00.000Z\"\n }\n ]\n}\n"},{"location":"api/history/#post-apihistoryorphan-rawimport","title":"POST /api/history/orphan-raw/import","text":"Importiert RAW-Ordner als FINISHED-Job.
Request:
{ \"rawPath\": \"/mnt/raw/Inception (2010) [tt1375666] - RAW - job-99\" }\n Response:
{\n \"job\": { \"id\": 77, \"status\": \"FINISHED\" },\n \"uiReset\": { \"reset\": true, \"state\": \"IDLE\" }\n}\n"},{"location":"api/history/#post-apihistoryidomdbassign","title":"POST /api/history/:id/omdb/assign","text":"Weist OMDb-/Metadaten nachtr\u00e4glich zu.
Request:
{\n \"imdbId\": \"tt1375666\",\n \"title\": \"Inception\",\n \"year\": 2010,\n \"poster\": \"https://...\",\n \"fromOmdb\": true\n}\n Response:
{ \"job\": { \"id\": 42, \"imdb_id\": \"tt1375666\" } }\n"},{"location":"api/history/#post-apihistoryiddelete-files","title":"POST /api/history/:id/delete-files","text":"L\u00f6scht Dateien eines Jobs, beh\u00e4lt DB-Eintrag.
Request:
{ \"target\": \"both\" }\n target: raw | movie | both
Response:
{\n \"summary\": {\n \"target\": \"both\",\n \"raw\": { \"attempted\": true, \"deleted\": true, \"filesDeleted\": 12, \"dirsRemoved\": 3, \"reason\": null },\n \"movie\": { \"attempted\": true, \"deleted\": false, \"filesDeleted\": 0, \"dirsRemoved\": 0, \"reason\": \"Movie-Datei/Pfad existiert nicht.\" }\n },\n \"job\": { \"id\": 42 }\n}\n"},{"location":"api/history/#post-apihistoryiddelete","title":"POST /api/history/:id/delete","text":"L\u00f6scht Job aus DB; optional auch Dateien.
Request:
{ \"target\": \"none\" }\n target: none | raw | movie | both
Response:
{\n \"deleted\": true,\n \"jobId\": 42,\n \"fileTarget\": \"both\",\n \"fileSummary\": {\n \"target\": \"both\",\n \"raw\": { \"filesDeleted\": 10 },\n \"movie\": { \"filesDeleted\": 1 }\n },\n \"uiReset\": {\n \"reset\": true,\n \"state\": \"IDLE\"\n }\n}\n"},{"location":"api/history/#hinweise","title":"Hinweise","text":"409).Endpunkte zur Steuerung des Pipeline-Workflows.
"},{"location":"api/pipeline/#get-apipipelinestate","title":"GET /api/pipeline/state","text":"Liefert aktuellen Pipeline- und Hardware-Monitoring-Snapshot.
Response (Beispiel):
{\n \"pipeline\": {\n \"state\": \"READY_TO_ENCODE\",\n \"activeJobId\": 42,\n \"progress\": 0,\n \"eta\": null,\n \"statusText\": \"Mediainfo best\u00e4tigt - Encode manuell starten\",\n \"context\": {\n \"jobId\": 42\n },\n \"jobProgress\": {\n \"42\": {\n \"state\": \"MEDIAINFO_CHECK\",\n \"progress\": 68.5,\n \"eta\": null,\n \"statusText\": \"MEDIAINFO_CHECK 68.50%\"\n }\n },\n \"queue\": {\n \"maxParallelJobs\": 1,\n \"runningCount\": 1,\n \"queuedCount\": 2,\n \"runningJobs\": [],\n \"queuedJobs\": []\n }\n },\n \"hardwareMonitoring\": {\n \"enabled\": true,\n \"intervalMs\": 5000,\n \"updatedAt\": \"2026-03-10T09:00:00.000Z\",\n \"sample\": {\n \"cpu\": {},\n \"memory\": {},\n \"gpu\": {},\n \"storage\": {}\n },\n \"error\": null\n }\n}\n"},{"location":"api/pipeline/#post-apipipelineanalyze","title":"POST /api/pipeline/analyze","text":"Startet Disc-Analyse und legt Job an.
Response:
{\n \"result\": {\n \"jobId\": 42,\n \"detectedTitle\": \"INCEPTION\",\n \"omdbCandidates\": []\n }\n}\n"},{"location":"api/pipeline/#post-apipipelinerescan-disc","title":"POST /api/pipeline/rescan-disc","text":"Erzwingt erneute Laufwerkspr\u00fcfung.
Response (Beispiel):
{\n \"result\": {\n \"present\": true,\n \"changed\": true,\n \"emitted\": \"discInserted\",\n \"device\": {\n \"path\": \"/dev/sr0\",\n \"discLabel\": \"INCEPTION\",\n \"mediaProfile\": \"bluray\"\n }\n }\n}\n"},{"location":"api/pipeline/#get-apipipelineomdbsearchq","title":"GET /api/pipeline/omdb/search?q= OMDb-Titelsuche.
Response:
{\n \"results\": [\n {\n \"imdbId\": \"tt1375666\",\n \"title\": \"Inception\",\n \"year\": \"2010\",\n \"type\": \"movie\",\n \"poster\": \"https://...\"\n }\n ]\n}\n","text":""},{"location":"api/pipeline/#post-apipipelineselect-metadata","title":"POST /api/pipeline/select-metadata Setzt Metadaten (und optional Playlist) f\u00fcr einen Job.
Request:
{\n \"jobId\": 42,\n \"title\": \"Inception\",\n \"year\": 2010,\n \"imdbId\": \"tt1375666\",\n \"poster\": \"https://...\",\n \"fromOmdb\": true,\n \"selectedPlaylist\": \"00800\"\n}\n Response:
{ \"job\": { \"id\": 42, \"status\": \"READY_TO_START\" } }\n","text":""},{"location":"api/pipeline/#post-apipipelinestartjobid","title":"POST /api/pipeline/start/:jobId Startet vorbereiteten Job oder queued ihn (je nach Parallel-Limit).
M\u00f6gliche Responses:
{ \"result\": { \"started\": true, \"stage\": \"RIPPING\" } }\n { \"result\": { \"queued\": true, \"started\": false, \"queuePosition\": 2, \"action\": \"START_PREPARED\" } }\n","text":""},{"location":"api/pipeline/#post-apipipelineconfirm-encodejobid","title":"POST /api/pipeline/confirm-encode/:jobId Best\u00e4tigt Review-Auswahl (Tracks, Pre/Post-Skripte/Ketten, User-Preset).
Request (typisch):
{\n \"selectedEncodeTitleId\": 1,\n \"selectedTrackSelection\": {\n \"1\": {\n \"audioTrackIds\": [1, 2],\n \"subtitleTrackIds\": [3]\n }\n },\n \"selectedPreEncodeScriptIds\": [1],\n \"selectedPostEncodeScriptIds\": [2, 7],\n \"selectedPreEncodeChainIds\": [3],\n \"selectedPostEncodeChainIds\": [4],\n \"selectedUserPresetId\": 5,\n \"skipPipelineStateUpdate\": false\n}\n Response:
{ \"job\": { \"id\": 42, \"encode_review_confirmed\": 1 } }\n","text":""},{"location":"api/pipeline/#post-apipipelinecancel","title":"POST /api/pipeline/cancel Bricht laufenden Job ab oder entfernt Queue-Eintrag.
Request (optional):
{ \"jobId\": 42 }\n M\u00f6gliche Responses:
{ \"result\": { \"cancelled\": true, \"queuedOnly\": true, \"jobId\": 42 } }\n { \"result\": { \"cancelled\": true, \"queuedOnly\": false, \"jobId\": 42 } }\n { \"result\": { \"cancelled\": true, \"queuedOnly\": false, \"pending\": true, \"jobId\": 42 } }\n","text":""},{"location":"api/pipeline/#post-apipipelineretryjobid","title":"POST /api/pipeline/retry/:jobId Retry f\u00fcr ERROR/CANCELLED-Jobs (oder Queue-Einreihung).
Startet Re-Encode aus bestehendem RAW.
","text":""},{"location":"api/pipeline/#post-apipipelinerestart-reviewjobid","title":"POST /api/pipeline/restart-review/:jobIdBerechnet Review aus RAW neu.
","text":""},{"location":"api/pipeline/#post-apipipelinerestart-encodejobid","title":"POST /api/pipeline/restart-encode/:jobIdStartet Encoding mit letzter best\u00e4tigter Review neu.
","text":""},{"location":"api/pipeline/#post-apipipelineresume-readyjobid","title":"POST /api/pipeline/resume-ready/:jobIdL\u00e4dt READY_TO_ENCODE-Job nach Neustart wieder in aktive Session.
Alle Endpunkte liefern { result: ... } bzw. { job: ... }.
Liefert Queue-Snapshot.
{\n \"queue\": {\n \"maxParallelJobs\": 1,\n \"runningCount\": 1,\n \"queuedCount\": 3,\n \"runningJobs\": [\n {\n \"jobId\": 41,\n \"title\": \"Inception\",\n \"status\": \"ENCODING\",\n \"lastState\": \"ENCODING\"\n }\n ],\n \"queuedJobs\": [\n {\n \"entryId\": 11,\n \"position\": 1,\n \"type\": \"job\",\n \"jobId\": 42,\n \"action\": \"START_PREPARED\",\n \"actionLabel\": \"Start\",\n \"title\": \"Matrix\",\n \"status\": \"READY_TO_ENCODE\",\n \"lastState\": \"READY_TO_ENCODE\",\n \"hasScripts\": true,\n \"hasChains\": false,\n \"enqueuedAt\": \"2026-03-10T09:00:00.000Z\"\n },\n {\n \"entryId\": 12,\n \"position\": 2,\n \"type\": \"wait\",\n \"waitSeconds\": 30,\n \"title\": \"Warten 30s\",\n \"status\": \"QUEUED\",\n \"enqueuedAt\": \"2026-03-10T09:01:00.000Z\"\n }\n ],\n \"updatedAt\": \"2026-03-10T09:01:02.000Z\"\n }\n}\n"},{"location":"api/pipeline/#post-apipipelinequeuereorder","title":"POST /api/pipeline/queue/reorder","text":"Sortiert Queue-Eintr\u00e4ge neu.
Request:
{\n \"orderedEntryIds\": [12, 11]\n}\n Legacy fallback wird akzeptiert:
{\n \"orderedJobIds\": [42, 43]\n}\n"},{"location":"api/pipeline/#post-apipipelinequeueentry","title":"POST /api/pipeline/queue/entry","text":"F\u00fcgt Nicht-Job-Queue-Eintrag hinzu (script, chain, wait).
Request-Beispiele:
{ \"type\": \"script\", \"scriptId\": 3 }\n { \"type\": \"chain\", \"chainId\": 2, \"insertAfterEntryId\": 11 }\n { \"type\": \"wait\", \"waitSeconds\": 45 }\n Response:
{\n \"result\": { \"entryId\": 12, \"type\": \"wait\", \"position\": 2 },\n \"queue\": { \"...\": \"...\" }\n}\n"},{"location":"api/pipeline/#delete-apipipelinequeueentryentryid","title":"DELETE /api/pipeline/queue/entry/:entryId","text":"Entfernt Queue-Eintrag.
Response:
{ \"queue\": { \"...\": \"...\" } }\n"},{"location":"api/pipeline/#pipeline-zustande","title":"Pipeline-Zust\u00e4nde State Bedeutung IDLE Wartet auf Medium DISC_DETECTED Medium erkannt ANALYZING MakeMKV-Analyse l\u00e4uft METADATA_SELECTION Metadaten-Auswahl WAITING_FOR_USER_DECISION Playlist-Entscheidung erforderlich READY_TO_START \u00dcbergang vor Start RIPPING MakeMKV-Rip l\u00e4uft MEDIAINFO_CHECK Titel-/Track-Auswertung READY_TO_ENCODE Review bereit ENCODING HandBrake-Encoding l\u00e4uft FINISHED Abgeschlossen CANCELLED Abgebrochen ERROR Fehler","text":""},{"location":"api/runtime-activities/","title":"Runtime Activities API","text":"Ripster verfolgt alle laufenden und k\u00fcrzlich abgeschlossenen Aktivit\u00e4ten (Skripte, Skript-Ketten, Cron-Jobs, interne Tasks) in Echtzeit \u00fcber den RuntimeActivityService.
Aktivit\u00e4ten entstehen, wenn Ripster intern Aktionen ausf\u00fchrt \u2013 z. B. beim Start eines Cron-Jobs, beim Ausf\u00fchren einer Skript-Kette oder beim Durchlaufen von Pipeline-Schritten. Sie sind nicht persistent (kein DB-Speicher) und werden nur im Arbeitsspeicher gehalten.
active): Laufen gerade.recent): Abgeschlossen, max. 120 Eintr\u00e4ge.\u00c4nderungen werden \u00fcber WebSocket (RUNTIME_ACTIVITY_CHANGED) in Echtzeit gesendet.
{\n \"id\": 7,\n \"type\": \"chain\",\n \"name\": \"Post-Encode Aufr\u00e4umen\",\n \"status\": \"running\",\n \"source\": \"cron\",\n \"message\": \"Schritt 2 von 3\",\n \"currentStep\": \"cleanup.sh\",\n \"currentStepType\": \"script\",\n \"currentScriptName\": \"cleanup.sh\",\n \"stepIndex\": 2,\n \"stepTotal\": 3,\n \"parentActivityId\": null,\n \"jobId\": 42,\n \"cronJobId\": 3,\n \"chainId\": 5,\n \"scriptId\": null,\n \"canCancel\": true,\n \"canNextStep\": false,\n \"outcome\": \"running\",\n \"errorMessage\": null,\n \"output\": null,\n \"stdout\": null,\n \"stderr\": null,\n \"stdoutTruncated\": false,\n \"stderrTruncated\": false,\n \"startedAt\": \"2026-03-10T10:00:00.000Z\",\n \"finishedAt\": null,\n \"durationMs\": null,\n \"exitCode\": null,\n \"success\": null\n}\n"},{"location":"api/runtime-activities/#felder","title":"Felder","text":"Feld Typ Beschreibung id number Eindeutige ID (Laufz\u00e4hler, nicht persistent) type string Art der Aktivit\u00e4t: script | chain | cron | task name string \\| null Anzeigename der Aktivit\u00e4t status string Aktueller Status: running | success | error source string \\| null Ausl\u00f6ser (z. B. cron, pipeline, manual) message string \\| null Kurztext zum aktuellen Zustand currentStep string \\| null Name des aktuell ausgef\u00fchrten Schritts currentStepType string \\| null Typ des Schritts (z. B. script, wait) currentScriptName string \\| null Name des Skripts im aktuellen Schritt stepIndex number \\| null Aktueller Schritt (1-basiert) stepTotal number \\| null Gesamtanzahl Schritte parentActivityId number \\| null ID der \u00fcbergeordneten Aktivit\u00e4t jobId number \\| null Verkn\u00fcpfte Job-ID cronJobId number \\| null Verkn\u00fcpfte Cron-Job-ID chainId number \\| null Verkn\u00fcpfte Skript-Ketten-ID scriptId number \\| null Verkn\u00fcpfte Skript-ID canCancel boolean Abbrechen \u00fcber API m\u00f6glich canNextStep boolean N\u00e4chster Schritt \u00fcber API ausl\u00f6sbar outcome string \\| null Abschluss-Ergebnis: success | error | cancelled | skipped | running errorMessage string \\| null Fehlermeldung (max. 2.000 Zeichen) output string \\| null Allgemeine Ausgabe (max. 12.000 Zeichen) stdout string \\| null Standardausgabe des Prozesses (max. 12.000 Zeichen) stderr string \\| null Fehlerausgabe des Prozesses (max. 12.000 Zeichen) stdoutTruncated boolean true, wenn stdout gek\u00fcrzt wurde stderrTruncated boolean true, wenn stderr gek\u00fcrzt wurde startedAt string ISO-8601-Zeitstempel des Starts finishedAt string \\| null ISO-8601-Zeitstempel des Endes durationMs number \\| null Laufzeit in Millisekunden exitCode number \\| null Exit-Code des Prozesses success boolean \\| null Erfolgsstatus (null bei laufender Aktivit\u00e4t)"},{"location":"api/runtime-activities/#snapshot-objekt","title":"Snapshot-Objekt","text":"Alle Aktivit\u00e4ts-Endpunkte geben einen Snapshot zur\u00fcck:
{\n \"active\": [ /* laufende Aktivit\u00e4ten, nach startedAt absteigend */ ],\n \"recent\": [ /* abgeschlossene Aktivit\u00e4ten, nach finishedAt absteigend, max. 120 */ ],\n \"updatedAt\": \"2026-03-10T10:05:00.000Z\"\n}\n"},{"location":"api/runtime-activities/#endpunkte","title":"Endpunkte","text":""},{"location":"api/runtime-activities/#get-apiactivities","title":"GET /api/activities","text":"Aktuellen Aktivit\u00e4ts-Snapshot abrufen.
Antwort:
{\n \"active\": [],\n \"recent\": [\n {\n \"id\": 5,\n \"type\": \"script\",\n \"name\": \"notify.sh\",\n \"status\": \"success\",\n \"outcome\": \"success\",\n \"startedAt\": \"2026-03-10T09:58:00.000Z\",\n \"finishedAt\": \"2026-03-10T09:58:02.000Z\",\n \"durationMs\": 2100,\n \"exitCode\": 0,\n \"success\": true,\n \"canCancel\": false,\n \"canNextStep\": false\n }\n ],\n \"updatedAt\": \"2026-03-10T10:05:00.000Z\"\n}\n"},{"location":"api/runtime-activities/#post-apiactivitiesidcancel","title":"POST /api/activities/:id/cancel","text":"Aktive Aktivit\u00e4t abbrechen (nur wenn canCancel: true).
Parameter:
Name In Typ Beschreibungid path number Aktivit\u00e4ts-ID reason body string Optionaler Abbruchgrund Request Body:
{ \"reason\": \"Manueller Abbruch durch Benutzer\" }\n Antwort (Erfolg):
{\n \"ok\": true,\n \"action\": null,\n \"snapshot\": { \"active\": [], \"recent\": [], \"updatedAt\": \"...\" }\n}\n Fehlercodes:
HTTP Bedeutung404 Aktivit\u00e4t nicht gefunden oder bereits abgeschlossen 409 Abbrechen wird von dieser Aktivit\u00e4t nicht unterst\u00fctzt"},{"location":"api/runtime-activities/#post-apiactivitiesidnext-step","title":"POST /api/activities/:id/next-step","text":"N\u00e4chsten Schritt einer Aktivit\u00e4t ausl\u00f6sen (nur wenn canNextStep: true).
Parameter:
Name In Typ Beschreibungid path number Aktivit\u00e4ts-ID Antwort (Erfolg):
{\n \"ok\": true,\n \"action\": null,\n \"snapshot\": { \"active\": [], \"recent\": [], \"updatedAt\": \"...\" }\n}\n Fehlercodes:
HTTP Bedeutung404 Aktivit\u00e4t nicht gefunden 409 N\u00e4chster Schritt wird von dieser Aktivit\u00e4t nicht unterst\u00fctzt"},{"location":"api/runtime-activities/#post-apiactivitiesclear-recent","title":"POST /api/activities/clear-recent","text":"Alle abgeschlossenen Aktivit\u00e4ten aus recent l\u00f6schen.
Antwort:
{\n \"ok\": true,\n \"removed\": 14,\n \"snapshot\": { \"active\": [], \"recent\": [], \"updatedAt\": \"...\" }\n}\n"},{"location":"api/runtime-activities/#grenzwerte","title":"Grenzwerte","text":"Wert Limit Maximale recent-Eintr\u00e4ge 120 Maximale L\u00e4nge stdout / stderr / output 12.000 Zeichen Maximale L\u00e4nge errorMessage / message 2.000 Zeichen Maximale L\u00e4nge outcome 40 Zeichen Gek\u00fcrzte Ausgaben erhalten den Suffix ...[gek\u00fcrzt] (bei Inline-Text) bzw. \\n...[gek\u00fcrzt] (bei mehrzeiligem Output).
\u00c4nderungen werden automatisch als RUNTIME_ACTIVITY_CHANGED WebSocket-Event gesendet. Die Frontend-Komponente braucht GET /api/activities nur beim initialen Laden aufzurufen.
Endpunkte f\u00fcr Einstellungen, Skripte, Skript-Ketten und User-Presets.
"},{"location":"api/settings/#get-apisettings","title":"GET /api/settings","text":"Liefert alle Einstellungen kategorisiert.
Response (Struktur):
{\n \"categories\": [\n {\n \"category\": \"Pfade\",\n \"settings\": [\n {\n \"key\": \"raw_dir\",\n \"label\": \"Raw Ausgabeordner\",\n \"type\": \"path\",\n \"required\": true,\n \"description\": \"...\",\n \"defaultValue\": \"data/output/raw\",\n \"options\": [],\n \"validation\": { \"minLength\": 1 },\n \"value\": \"data/output/raw\",\n \"orderIndex\": 100\n }\n ]\n }\n ]\n}\n"},{"location":"api/settings/#put-apisettingskey","title":"PUT /api/settings/:key","text":"Aktualisiert eine einzelne Einstellung.
Request:
{ \"value\": \"/mnt/storage/raw\" }\n Response:
{\n \"setting\": {\n \"key\": \"raw_dir\",\n \"value\": \"/mnt/storage/raw\"\n },\n \"reviewRefresh\": {\n \"triggered\": false,\n \"reason\": \"not_ready\"\n }\n}\n reviewRefresh ist null oder ein Objekt mit Status der optionalen Review-Neuberechnung.
Aktualisiert mehrere Einstellungen atomar.
Request:
{\n \"settings\": {\n \"raw_dir\": \"/mnt/storage/raw\",\n \"movie_dir\": \"/mnt/storage/movies\",\n \"handbrake_preset_bluray\": \"H.264 MKV 1080p30\"\n }\n}\n Response:
{\n \"changes\": [\n { \"key\": \"raw_dir\", \"value\": \"/mnt/storage/raw\" },\n { \"key\": \"movie_dir\", \"value\": \"/mnt/storage/movies\" }\n ],\n \"reviewRefresh\": {\n \"triggered\": true,\n \"jobId\": 42,\n \"relevantKeys\": [\"handbrake_preset_bluray\"]\n }\n}\n Bei Validierungsfehlern kommt 400 mit error.details[].
Liest Preset-Liste via HandBrakeCLI -z (mit Fallback auf konfigurierte Presets).
Response (Beispiel):
{\n \"source\": \"handbrake-cli\",\n \"message\": null,\n \"options\": [\n { \"label\": \"General/\", \"value\": \"__group__general\", \"disabled\": true, \"category\": \"General\" },\n { \"label\": \" Fast 1080p30\", \"value\": \"Fast 1080p30\", \"category\": \"General\" }\n ]\n}\n"},{"location":"api/settings/#post-apisettingspushovertest","title":"POST /api/settings/pushover/test","text":"Sendet Testnachricht \u00fcber aktuelle PushOver-Settings.
Request (optional):
{\n \"title\": \"Test\",\n \"message\": \"Ripster Test\"\n}\n Response:
{\n \"result\": {\n \"sent\": true,\n \"eventKey\": \"test\",\n \"requestId\": \"...\"\n }\n}\n Wenn PushOver deaktiviert ist oder Credentials fehlen, kommt i. d. R. ebenfalls 200 mit sent: false + reason.
Basis: /api/settings/scripts
{ \"scripts\": [ { \"id\": 1, \"name\": \"...\", \"scriptBody\": \"...\", \"orderIndex\": 1, \"createdAt\": \"...\", \"updatedAt\": \"...\" } ] }\n"},{"location":"api/settings/#post-apisettingsscripts","title":"POST /api/settings/scripts","text":"{ \"name\": \"Move\", \"scriptBody\": \"mv \\\"$RIPSTER_OUTPUT_PATH\\\" /mnt/movies/\" }\n Response: 201 mit { \"script\": { ... } }
Body wie POST, Response { \"script\": { ... } }.
Response { \"removed\": { ... } }.
{ \"orderedScriptIds\": [3, 1, 2] }\n Response { \"scripts\": [ ... ] }.
F\u00fchrt Skript als Testlauf aus.
{\n \"result\": {\n \"scriptId\": 1,\n \"scriptName\": \"Move\",\n \"success\": true,\n \"exitCode\": 0,\n \"signal\": null,\n \"timedOut\": false,\n \"durationMs\": 120,\n \"stdout\": \"...\",\n \"stderr\": \"...\",\n \"stdoutTruncated\": false,\n \"stderrTruncated\": false\n }\n}\n"},{"location":"api/settings/#umgebungsvariablen-fur-skripte","title":"Umgebungsvariablen f\u00fcr Skripte","text":"Diese Variablen werden beim Ausf\u00fchren gesetzt:
RIPSTER_SCRIPT_RUN_ATRIPSTER_JOB_IDRIPSTER_JOB_TITLERIPSTER_MODERIPSTER_INPUT_PATHRIPSTER_OUTPUT_PATHRIPSTER_RAW_PATHRIPSTER_SCRIPT_IDRIPSTER_SCRIPT_NAMERIPSTER_SCRIPT_SOURCEBasis: /api/settings/script-chains
Eine Kette hat Schritte vom Typ:
script (scriptId erforderlich)wait (waitSeconds 1..3600)Response { \"chains\": [ ... ] } (inkl. steps[]).
Response { \"chain\": { ... } }.
{\n \"name\": \"After Encode\",\n \"steps\": [\n { \"stepType\": \"script\", \"scriptId\": 1 },\n { \"stepType\": \"wait\", \"waitSeconds\": 15 },\n { \"stepType\": \"script\", \"scriptId\": 2 }\n ]\n}\n Response: 201 mit { \"chain\": { ... } }
Body wie POST, Response { \"chain\": { ... } }.
Response { \"removed\": { ... } }.
{ \"orderedChainIds\": [2, 1, 3] }\n Response { \"chains\": [ ... ] }.
Response:
{\n \"result\": {\n \"chainId\": 2,\n \"chainName\": \"After Encode\",\n \"steps\": 3,\n \"succeeded\": 3,\n \"failed\": 0,\n \"aborted\": false,\n \"results\": []\n }\n}\n"},{"location":"api/settings/#user-presets","title":"User-Presets","text":"Basis: /api/settings/user-presets
Optionaler Query-Parameter: media_type=bluray|dvd|other|all
{\n \"presets\": [\n {\n \"id\": 1,\n \"name\": \"Blu-ray HQ\",\n \"mediaType\": \"bluray\",\n \"handbrakePreset\": \"H.264 MKV 1080p30\",\n \"extraArgs\": \"--encoder-preset slow\",\n \"description\": \"...\",\n \"createdAt\": \"...\",\n \"updatedAt\": \"...\"\n }\n ]\n}\n"},{"location":"api/settings/#post-apisettingsuser-presets","title":"POST /api/settings/user-presets","text":"{\n \"name\": \"Blu-ray HQ\",\n \"mediaType\": \"bluray\",\n \"handbrakePreset\": \"H.264 MKV 1080p30\",\n \"extraArgs\": \"--encoder-preset slow\",\n \"description\": \"optional\"\n}\n Response: 201 mit { \"preset\": { ... } }
Body mit beliebigen Feldern aus POST, Response { \"preset\": { ... } }.
Response { \"removed\": { ... } }.
Ripster sendet Echtzeit-Updates \u00fcber /ws.
const ws = new WebSocket('ws://localhost:3001/ws');\n\nws.onmessage = (event) => {\n const msg = JSON.parse(event.data);\n console.log(msg.type, msg.payload);\n};\n"},{"location":"api/websocket/#nachrichtenformat","title":"Nachrichtenformat","text":"Die meisten Broadcasts haben dieses Schema:
{\n \"type\": \"EVENT_TYPE\",\n \"payload\": {},\n \"timestamp\": \"2026-03-10T09:00:00.000Z\"\n}\n Ausnahme: WS_CONNECTED beim Verbindungsaufbau enth\u00e4lt kein timestamp.
Sofort nach erfolgreicher Verbindung.
{\n \"type\": \"WS_CONNECTED\",\n \"payload\": {\n \"connectedAt\": \"2026-03-10T09:00:00.000Z\"\n }\n}\n"},{"location":"api/websocket/#pipeline_state_changed","title":"PIPELINE_STATE_CHANGED","text":"Neuer Pipeline-Snapshot.
{\n \"type\": \"PIPELINE_STATE_CHANGED\",\n \"payload\": {\n \"state\": \"ENCODING\",\n \"activeJobId\": 42,\n \"progress\": 62.5,\n \"eta\": \"00:12:34\",\n \"statusText\": \"ENCODING 62.50%\",\n \"context\": {},\n \"jobProgress\": {\n \"42\": {\n \"state\": \"ENCODING\",\n \"progress\": 62.5,\n \"eta\": \"00:12:34\",\n \"statusText\": \"ENCODING 62.50%\"\n }\n },\n \"queue\": {\n \"maxParallelJobs\": 1,\n \"runningCount\": 1,\n \"queuedCount\": 2,\n \"runningJobs\": [],\n \"queuedJobs\": []\n }\n }\n}\n"},{"location":"api/websocket/#pipeline_progress","title":"PIPELINE_PROGRESS","text":"Laufende Fortschrittsupdates.
{\n \"type\": \"PIPELINE_PROGRESS\",\n \"payload\": {\n \"state\": \"ENCODING\",\n \"activeJobId\": 42,\n \"progress\": 62.5,\n \"eta\": \"00:12:34\",\n \"statusText\": \"ENCODING 62.50%\"\n }\n}\n"},{"location":"api/websocket/#pipeline_queue_changed","title":"PIPELINE_QUEUE_CHANGED","text":"Queue-Snapshot aktualisiert.
"},{"location":"api/websocket/#disc_detected-disc_removed","title":"DISC_DETECTED / DISC_REMOVED","text":"Disc-Insertion/-Removal.
{\n \"type\": \"DISC_DETECTED\",\n \"payload\": {\n \"device\": {\n \"path\": \"/dev/sr0\",\n \"discLabel\": \"INCEPTION\",\n \"model\": \"ASUS BW-16D1HT\",\n \"fstype\": \"udf\",\n \"mountpoint\": null,\n \"mediaProfile\": \"bluray\"\n }\n }\n}\n mediaProfile: bluray | dvd | other | null
Snapshot aus Hardware-Monitoring.
{\n \"type\": \"HARDWARE_MONITOR_UPDATE\",\n \"payload\": {\n \"enabled\": true,\n \"intervalMs\": 5000,\n \"updatedAt\": \"2026-03-10T09:00:00.000Z\",\n \"sample\": {\n \"cpu\": {},\n \"memory\": {},\n \"gpu\": {},\n \"storage\": {}\n },\n \"error\": null\n }\n}\n"},{"location":"api/websocket/#pipeline_error","title":"PIPELINE_ERROR","text":"Fehler bei Disc-Event-Verarbeitung in Pipeline.
"},{"location":"api/websocket/#disk_detection_error","title":"DISK_DETECTION_ERROR","text":"Fehler in Laufwerkserkennung.
"},{"location":"api/websocket/#settings_updated","title":"SETTINGS_UPDATED","text":"Einzelnes Setting wurde gespeichert.
"},{"location":"api/websocket/#settings_bulk_updated","title":"SETTINGS_BULK_UPDATED","text":"Bulk-Settings gespeichert.
{\n \"type\": \"SETTINGS_BULK_UPDATED\",\n \"payload\": {\n \"count\": 3,\n \"keys\": [\"raw_dir\", \"movie_dir\", \"handbrake_preset_bluray\"]\n }\n}\n"},{"location":"api/websocket/#settings_scripts_updated","title":"SETTINGS_SCRIPTS_UPDATED","text":"Skript ge\u00e4ndert (created|updated|deleted|reordered).
Skript-Kette ge\u00e4ndert (created|updated|deleted|reordered).
User-Preset ge\u00e4ndert (created|updated|deleted).
Cron-Config ge\u00e4ndert (created|updated|deleted).
Laufzeitstatus eines Cron-Jobs ge\u00e4ndert.
{\n \"type\": \"CRON_JOB_UPDATED\",\n \"payload\": {\n \"id\": 1,\n \"lastRunStatus\": \"running\",\n \"lastRunAt\": \"2026-03-10T10:00:00.000Z\",\n \"nextRunAt\": null\n }\n}\n"},{"location":"api/websocket/#runtime_activity_changed","title":"RUNTIME_ACTIVITY_CHANGED","text":"Vollst\u00e4ndiger Snapshot aller laufenden und k\u00fcrzlich abgeschlossenen Aktivit\u00e4ten.
Wird ausgel\u00f6st, wenn eine Aktivit\u00e4t gestartet, aktualisiert oder abgeschlossen wird sowie nach clear-recent.
{\n \"type\": \"RUNTIME_ACTIVITY_CHANGED\",\n \"payload\": {\n \"active\": [\n {\n \"id\": 7,\n \"type\": \"chain\",\n \"name\": \"Post-Encode Aufr\u00e4umen\",\n \"status\": \"running\",\n \"source\": \"cron\",\n \"message\": \"Schritt 2 von 3\",\n \"currentStep\": \"cleanup.sh\",\n \"currentStepType\": \"script\",\n \"stepIndex\": 2,\n \"stepTotal\": 3,\n \"canCancel\": true,\n \"canNextStep\": false,\n \"outcome\": \"running\",\n \"startedAt\": \"2026-03-10T10:00:00.000Z\",\n \"finishedAt\": null,\n \"durationMs\": null\n }\n ],\n \"recent\": [],\n \"updatedAt\": \"2026-03-10T10:00:05.000Z\"\n }\n}\n Vollst\u00e4ndige Feldbeschreibung: Runtime Activities API.
"},{"location":"api/websocket/#reconnect-verhalten","title":"Reconnect-Verhalten","text":"useWebSocket verbindet bei Abbruch automatisch neu:
1500msDieser Bereich enth\u00e4lt die technische Referenz hinter dem Benutzerhandbuch.
"},{"location":"appendix/#inhalt","title":"Inhalt","text":"Ripster ist eine Client-Server-Anwendung mit REST + WebSocket und externen CLI-Tools.
"},{"location":"architecture/#systemuberblick","title":"System\u00fcberblick","text":"graph TB\n subgraph Browser[\"Browser (React)\"]\n Dashboard[Dashboard]\n Settings[Einstellungen]\n History[Historie]\n end\n\n subgraph Backend[\"Node.js Backend\"]\n API[REST API\\nExpress]\n WS[WebSocket\\n/ws]\n Pipeline[pipelineService]\n Cron[cronService]\n DB[(SQLite)]\n end\n\n subgraph Tools[\"Externe Tools\"]\n MakeMKV[makemkvcon]\n HandBrake[HandBrakeCLI]\n MediaInfo[mediainfo]\n end\n\n Browser <-->|HTTP| API\n Browser <-->|WebSocket| WS\n Pipeline --> MakeMKV\n Pipeline --> HandBrake\n Pipeline --> MediaInfo\n API --> DB\n Pipeline --> DB\n Cron --> DB"},{"location":"architecture/#details","title":"Details","text":"Das Backend ist in Services aufgeteilt, die von Express-Routen orchestriert werden.
"},{"location":"architecture/backend/#pipelineservicejs","title":"pipelineService.js","text":"Zentrale Workflow-Orchestrierung.
Aufgaben:
pipeline_state)script|chain|wait Eintr\u00e4ge)Wichtige Methoden:
analyzeDisc()selectMetadata()startPreparedJob()confirmEncodeReview()cancel()retry()reencodeFromRaw()restartReviewFromRaw()restartEncodeWithLastSettings()resumeReadyToEncodeJob()enqueueNonJobEntry(), reorderQueue(), removeQueueEntry()diskDetectionService.js","text":"Pollt Laufwerk(e) und emittiert:
discInserteddiscRemovederrorZusatz:
auto oder explicitmediaProfile-Erkennung (bluray/dvd/other)rescanAndEmit() f\u00fcr manuellen TriggersettingsService.js","text":"Settings-Layer mit Validation/Serialisierung.
Features:
getCategorizedSettings() f\u00fcr UI-FormsetSettingValue() / setSettingsBulk()resolveEffectiveToolSettings)HandBrakeCLI -zmakemkv_registration_keyhistoryService.js","text":"Historie + Dateioperationen.
Features:
raw|movie|both)none|raw|movie|both)cronService.js","text":"Integriertes Cron-System ohne externe Parser-Library.
Features:
nextRun-Berechnungscript oder chaincron_run_logs)CRON_JOBS_UPDATED, CRON_JOB_UPDATEDruntimeActivityService.js","text":"In-Memory-Tracking aller laufenden und k\u00fcrzlich abgeschlossenen Aktivit\u00e4ten (Skripte, Ketten, Cron-Jobs, Tasks).
Features:
startActivity(type, payload) \u2192 Aktivit\u00e4t registrieren, ID zur\u00fcckgebenupdateActivity(id, patch) \u2192 Laufende Aktivit\u00e4t aktualisierencompleteActivity(id, payload) \u2192 Aktivit\u00e4t abschlie\u00dfen und in recent verschiebensetControls(id, { cancel, nextStep }) \u2192 Steuer-Handler registrieren (f\u00fcr canCancel/canNextStep)requestCancel(id) / requestNextStep(id) \u2192 Steuer-Handler aufrufenclearRecent() \u2192 Abgeschlossene Aktivit\u00e4ten l\u00f6schengetSnapshot() \u2192 Snapshot mit active + recent + updatedAtRUNTIME_ACTIVITY_CHANGED \u00fcber WebSocket bei jeder \u00c4nderungLimits:
recent max. 120 Eintr\u00e4gestdout/stderr/output max. 12.000 Zeichenmessage/errorMessage max. 2.000 ZeichenVollst\u00e4ndige API-Dokumentation: Runtime Activities API
"},{"location":"architecture/backend/#weitere-services","title":"Weitere Services","text":"scriptService.js (CRUD + Test + Wrapper-Ausf\u00fchrung)scriptChainService.js (CRUD + Step-Execution)userPresetService.js (HandBrake User-Presets)hardwareMonitorService.js (CPU/RAM/GPU/Storage)websocketService.js (Client-Registry + Broadcast)notificationService.js (PushOver)logger.js (rotierende Datei-Logs)src/index.js)","text":"Beim Start:
/wsRipster verwendet SQLite (backend/data/ripster.db).
settings_schema\nsettings_values\njobs\npipeline_state\nscripts\nscript_chains\nscript_chain_steps\nuser_presets\ncron_jobs\ncron_run_logs\n"},{"location":"architecture/database/#jobs","title":"jobs","text":"Speichert Pipeline-Lifecycle und Artefakte pro Job.
Zentrale Felder:
title, year, imdb_id, poster_url, omdb_json, selected_from_omdbstart_time, end_time, status, last_stateraw_path, output_path, encode_input_pathmakemkv_info_json, handbrake_info_json, mediainfo_info_json, encode_plan_jsonencode_review_confirmed, rip_successful, error_messagecreated_at, updated_atpipeline_state","text":"Singleton-Tabelle (id = 1) f\u00fcr aktiven Snapshot:
stateactive_job_idprogressetastatus_textcontext_jsonupdated_atsettings_schema + settings_values","text":"settings_schema: Definition (Typ, Default, Validation, Reihenfolge)settings_values: aktueller Wert pro Keyscripts, script_chains, script_chain_steps","text":"scripts: Shell-Skripte (name, script_body, order_index)script_chains: Ketten (name, order_index)script_chain_steps: Schritte je Kettestep_type: script oder waitscript_id oder wait_secondsuser_presets","text":"Benannte HandBrake-Preset-Sets:
namemedia_type (bluray|dvd|other|all)handbrake_presetextra_argsdescriptioncron_jobs + cron_run_logs","text":"cron_jobs: Zeitplan + Statuscron_run_logs: einzelne L\u00e4ufestatus: running|success|erroroutputerror_messageBeim Start werden Schema und Settings-Metadaten automatisch abgeglichen.
Bei korruptem SQLite-File:
backend/data/corrupt-backups/ verschobensqlite3 backend/data/ripster.db\n\n.mode table\nSELECT id, status, title, created_at FROM jobs ORDER BY created_at DESC;\nSELECT key, value FROM settings_values ORDER BY key;\n"},{"location":"architecture/frontend/","title":"Frontend-Komponenten","text":"Frontend: React + PrimeReact + Vite.
"},{"location":"architecture/frontend/#hauptseiten","title":"Hauptseiten","text":""},{"location":"architecture/frontend/#dashboardpagejsx","title":"DashboardPage.jsx","text":"Pipeline-Steuerung:
SettingsPage.jsx","text":"Konfiguration:
DynamicSettingsForm)CronJobsTab)HistoryPage.jsx","text":"Historie:
PipelineStatusCard.jsxMetadataSelectionDialog.jsxMediaInfoReviewPanel.jsxJobDetailDialog.jsxCronJobsTab.jsxapi/client.js)","text":"request() mit JSON-HandlingError(message) gemapptVITE_API_BASE default /apihooks/useWebSocket.js)","text":"VITE_WS_URL oder automatisch ws(s)://<host>/wsIn App.jsx werden u. a. verarbeitet:
PIPELINE_STATE_CHANGEDPIPELINE_PROGRESSPIPELINE_QUEUE_CHANGEDDISC_DETECTED / DISC_REMOVEDHARDWARE_MONITOR_UPDATE# dev\nnpm run dev --prefix frontend\n\n# prod build\nnpm run build --prefix frontend\n"},{"location":"architecture/overview/","title":"Architektur-\u00dcbersicht","text":""},{"location":"architecture/overview/#kernprinzipien","title":"Kernprinzipien","text":""},{"location":"architecture/overview/#event-getriebene-pipeline","title":"Event-getriebene Pipeline","text":"pipelineService h\u00e4lt einen Snapshot der State-Machine und broadcastet \u00c4nderungen sofort via WebSocket.
State-\u00c4nderung -> PIPELINE_STATE_CHANGED/PIPELINE_PROGRESS -> Frontend-Update\n"},{"location":"architecture/overview/#service-layer","title":"Service-Layer","text":"Route -> Service -> DB/Tool-Execution\n Routes enthalten kaum Business-Logik.
"},{"location":"architecture/overview/#schema-getriebene-settings","title":"Schema-getriebene Settings","text":"Settings sind DB-schema-getrieben (settings_schema + settings_values), UI rendert dynamisch aus diesen Daten.
WebSocket l\u00e4uft auf /ws.
Wichtige Events:
PIPELINE_STATE_CHANGED, PIPELINE_PROGRESS, PIPELINE_QUEUE_CHANGEDDISC_DETECTED, DISC_REMOVEDHARDWARE_MONITOR_UPDATESETTINGS_UPDATED, SETTINGS_BULK_UPDATEDSETTINGS_SCRIPTS_UPDATED, SETTINGS_SCRIPT_CHAINS_UPDATED, USER_PRESETS_UPDATEDCRON_JOBS_UPDATED, CRON_JOB_UPDATEDPIPELINE_ERROR, DISK_DETECTION_ERRORExterne Tools werden als Child-Processes gestartet (processRunner):
progressParsers.js)SQLite-Datei: backend/data/ripster.db
Kern-Tabellen:
jobs, pipeline_statesettings_schema, settings_valuesscripts, script_chains, script_chain_stepsuser_presetscron_jobs, cron_run_logsBeim Start werden Schema und Settings-Migrationen automatisch ausgef\u00fchrt.
"},{"location":"architecture/overview/#fehlerbehandlung","title":"Fehlerbehandlung","text":"Zentrales Error-Handling liefert:
{\n \"error\": {\n \"message\": \"...\",\n \"statusCode\": 400,\n \"reqId\": \"...\",\n \"details\": []\n }\n}\n Fehlgeschlagene Jobs bleiben in der Historie (ERROR oder CANCELLED) und k\u00f6nnen erneut gestartet werden.
CORS_ORIGIN default: *LOG_LEVEL default: infoDB_PATH/LOG_DIR konfigurierbarDieser Abschnitt ist die technische Referenz zu allen Konfigurationsarten in Ripster.
"},{"location":"configuration/#inhalte","title":"Inhalte","text":"Einstellungsreferenz
Vollst\u00e4ndige Liste aller UI-Settings (Typ, Default, Hinweise).
Einstellungsreferenz
Umgebungsvariablen
backend/.env und frontend/.env inkl. Priorit\u00e4ten.
Umgebungsvariablen
Umgebungsvariablen steuern Backend/Vite au\u00dferhalb der DB-basierten UI-Settings.
"},{"location":"configuration/environment/#backend-backendenv","title":"Backend (backend/.env)","text":"Variable Default (Code) Beschreibung PORT 3001 Express-Port DB_PATH backend/data/ripster.db SQLite-Datei (relativ zu backend/) LOG_DIR backend/logs Fallback-Logverzeichnis (wenn log_dir-Setting nicht gesetzt/lesbar) CORS_ORIGIN * CORS-Origin f\u00fcr API LOG_LEVEL info debug, info, warn, error Beispiel:
PORT=3001\nDB_PATH=/var/lib/ripster/ripster.db\nLOG_DIR=/var/log/ripster\nCORS_ORIGIN=http://192.168.1.50:5173\nLOG_LEVEL=info\n Hinweis: backend/.env.example enth\u00e4lt bewusst dev-freundliche Werte (z. B. lokaler CORS_ORIGIN).
frontend/.env)","text":"Variable Default Beschreibung VITE_API_BASE /api API-Basis f\u00fcr Fetch-Client VITE_WS_URL automatisch aus window.location + /ws Optional explizite WebSocket-URL VITE_PUBLIC_ORIGIN leer \u00d6ffentliche Vite-Origin (Remote-Dev) VITE_ALLOWED_HOSTS true Komma-separierte Hostliste f\u00fcr Vite allowedHosts VITE_HMR_PROTOCOL abgeleitet aus VITE_PUBLIC_ORIGIN HMR-Protokoll (ws/wss) VITE_HMR_HOST abgeleitet aus VITE_PUBLIC_ORIGIN HMR-Host VITE_HMR_CLIENT_PORT abgeleitet aus VITE_PUBLIC_ORIGIN HMR-Client-Port Beispiele:
# lokal (mit Vite-Proxy)\nVITE_API_BASE=/api\n # remote dev\nVITE_API_BASE=http://192.168.1.50:3001/api\nVITE_WS_URL=ws://192.168.1.50:3001/ws\nVITE_PUBLIC_ORIGIN=http://192.168.1.50:5173\nVITE_ALLOWED_HOSTS=192.168.1.50,ripster.local\nVITE_HMR_PROTOCOL=ws\nVITE_HMR_HOST=192.168.1.50\nVITE_HMR_CLIENT_PORT=5173\n"},{"location":"configuration/environment/#prioritat","title":"Priorit\u00e4t","text":".envAlle Settings liegen in settings_schema/settings_values und werden \u00fcber die UI verwaltet.
Ripster arbeitet mit Media-Profilen:
bluraydvdotherViele Tool-/Pfad-Settings existieren als Profil-Varianten (*_bluray, *_dvd, *_other).
Wichtig:
raw_dir, movie_dir und die zugeh\u00f6rigen *_owner-Keys gibt es kein Cross-Profil-Fallback.Datei-/Ordner-Templates unterst\u00fctzen:
${title}${year}${imdbId}Nicht gesetzte Werte werden zu unknown.
raw_dir path data/output/raw raw_dir_bluray path null raw_dir_dvd path null raw_dir_other path null raw_dir_bluray_owner string null raw_dir_dvd_owner string null raw_dir_other_owner string null movie_dir path data/output/movies movie_dir_bluray path null movie_dir_dvd path null movie_dir_other path null movie_dir_bluray_owner string null movie_dir_dvd_owner string null movie_dir_other_owner string null log_dir path data/logs"},{"location":"configuration/settings-reference/#kategorie-laufwerk","title":"Kategorie: Laufwerk","text":"Key Typ Default Hinweis drive_mode select auto auto oder explicit drive_device path /dev/sr0 bei explicit relevant makemkv_source_index number 0 MakeMKV Source-Index disc_poll_interval_ms number 4000 1000..60000"},{"location":"configuration/settings-reference/#kategorie-monitoring","title":"Kategorie: Monitoring","text":"Key Typ Default hardware_monitoring_enabled boolean true hardware_monitoring_interval_ms number 5000"},{"location":"configuration/settings-reference/#kategorie-tools-global","title":"Kategorie: Tools (global)","text":"Key Typ Default makemkv_command string makemkvcon makemkv_registration_key string null mediainfo_command string mediainfo makemkv_min_length_minutes number 60 handbrake_command string HandBrakeCLI handbrake_restart_delete_incomplete_output boolean true pipeline_max_parallel_jobs number 1"},{"location":"configuration/settings-reference/#blu-ray-spezifisch","title":"Blu-ray-spezifisch","text":"Key Typ Default mediainfo_extra_args_bluray string null makemkv_rip_mode_bluray select backup makemkv_analyze_extra_args_bluray string null makemkv_rip_extra_args_bluray string null handbrake_preset_bluray string H.264 MKV 1080p30 handbrake_extra_args_bluray string null output_extension_bluray select mkv filename_template_bluray string ${title} (${year}) output_folder_template_bluray string null"},{"location":"configuration/settings-reference/#dvd-spezifisch","title":"DVD-spezifisch","text":"Key Typ Default mediainfo_extra_args_dvd string null makemkv_rip_mode_dvd select mkv makemkv_analyze_extra_args_dvd string null makemkv_rip_extra_args_dvd string null handbrake_preset_dvd string H.264 MKV 480p30 handbrake_extra_args_dvd string null output_extension_dvd select mkv filename_template_dvd string ${title} (${year}) output_folder_template_dvd string null"},{"location":"configuration/settings-reference/#kategorie-metadaten","title":"Kategorie: Metadaten","text":"Key Typ Default omdb_api_key string null omdb_default_type select movie"},{"location":"configuration/settings-reference/#kategorie-benachrichtigungen-pushover","title":"Kategorie: Benachrichtigungen (PushOver)","text":"Key Typ Default pushover_enabled boolean false pushover_token string null pushover_user string null pushover_device string null pushover_title_prefix string Ripster pushover_priority number 0 pushover_timeout_ms number 7000 pushover_notify_metadata_ready boolean true pushover_notify_rip_started boolean true pushover_notify_encoding_started boolean true pushover_notify_job_finished boolean true pushover_notify_job_error boolean true pushover_notify_job_cancelled boolean true pushover_notify_reencode_started boolean true pushover_notify_reencode_finished boolean true"},{"location":"configuration/settings-reference/#entfernte-legacy-keys","title":"Entfernte Legacy-Keys","text":"Diese Legacy-Keys werden bei Migration entfernt und sollten nicht mehr genutzt werden:
makemkv_backup_modemediainfo_extra_argsmakemkv_rip_modemakemkv_analyze_extra_argsmakemkv_rip_extra_argshandbrake_presethandbrake_extra_argsoutput_extensionfilename_templateoutput_folder_templatepushover_notify_disc_detectedTechnische Betriebsdokumentation f\u00fcr Entwicklung und Produktion.
Entwicklungsumgebung
Lokale Entwicklung mit Hot-Reload.
Entwicklung
Produktion
Installation und Betrieb auf Servern.
Produktion
makemkvcon, HandBrakeCLI, mediainfo)./start.sh\n Startet:
http://localhost:3001, mit nodemon)http://localhost:5173, mit Vite HMR)Stoppen: Ctrl+C.
cd backend\nnpm install\nnpm run dev\n"},{"location":"deployment/development/#frontend","title":"Frontend","text":"cd frontend\nnpm install\nnpm run dev\n"},{"location":"deployment/development/#vite-proxy-dev","title":"Vite-Proxy (Dev)","text":"frontend/vite.config.js proxied standardm\u00e4\u00dfig:
/api -> http://127.0.0.1:3001/ws -> ws://127.0.0.1:3001Beispiel frontend/.env.local:
VITE_API_BASE=http://192.168.1.100:3001/api\nVITE_WS_URL=ws://192.168.1.100:3001/ws\nVITE_PUBLIC_ORIGIN=http://192.168.1.100:5173\nVITE_ALLOWED_HOSTS=192.168.1.100,ripster.local\nVITE_HMR_PROTOCOL=ws\nVITE_HMR_HOST=192.168.1.100\nVITE_HMR_CLIENT_PORT=5173\n"},{"location":"deployment/development/#nutzliche-kommandos","title":"N\u00fctzliche Kommandos","text":"# Root dev (backend + frontend)\nnpm run dev\n\n# einzeln\nnpm run dev:backend\nnpm run dev:frontend\n\n# Frontend Build\nnpm run build:frontend\n"},{"location":"deployment/production/","title":"Produktions-Deployment","text":""},{"location":"deployment/production/#automatische-installation-empfohlen","title":"Automatische Installation (empfohlen)","text":"Das mitgelieferte install.sh richtet Ripster vollautomatisch auf Debian/Ubuntu ein \u2013 inklusive Node.js, MakeMKV, HandBrake, nginx und systemd-Dienst.
Unterst\u00fctzte Systeme: Debian 11/12, Ubuntu 22.04/24.04 Voraussetzung: root-Rechte, Internetzugang
"},{"location":"deployment/production/#schnellstart-via-curl","title":"Schnellstart via curl","text":"curl -fsSL https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh | sudo bash\n Oder mit wget:
wget -qO- https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh | sudo bash\n Optionen nur via Datei
Beim Pipen von curl/wget k\u00f6nnen keine Argumente \u00fcbergeben werden. F\u00fcr benutzerdefinierte Optionen zuerst herunterladen und dann mit sudo bash install.sh [Optionen] ausf\u00fchren.
--branch <branch> main Git-Branch f\u00fcr die Installation --dir <pfad> /opt/ripster Installationsverzeichnis --user <benutzer> ripster Systembenutzer f\u00fcr den Dienst --port <port> 3001 Backend-Port --host <hostname> Auto (Maschinen-IP) Hostname/IP f\u00fcr die Weboberfl\u00e4che --no-makemkv \u2013 MakeMKV-Installation \u00fcberspringen --no-handbrake \u2013 HandBrake-Installation \u00fcberspringen --no-nginx \u2013 nginx-Einrichtung \u00fcberspringen --reinstall \u2013 Bestehende Installation aktualisieren (Daten bleiben erhalten) -h, --help \u2013 Hilfe anzeigen"},{"location":"deployment/production/#beispiele","title":"Beispiele","text":"# Standard-Installation\nsudo bash install.sh\n\n# Anderen Branch und Port verwenden\nsudo bash install.sh --branch dev --port 8080\n\n# Ohne MakeMKV (bereits installiert)\nsudo bash install.sh --no-makemkv\n\n# Bestehende Installation aktualisieren\nsudo bash install.sh --reinstall\n\n# Ohne nginx (eigener Reverse-Proxy)\nsudo bash install.sh --no-nginx --host mein-server.local\n"},{"location":"deployment/production/#was-das-skript-erledigt","title":"Was das Skript erledigt","text":"curl, wget, git, mediainfo, udev u. a.--no-makemkv \u00fcbersprungen werden)apt install handbrake-cli)bin/HandBrakeCLIripster \u2013 ohne Login-Shell, Gruppen: cdrom, optical, disk, video, render--dir (bei --reinstall: sichert DB, pullt, stellt DB wieder her)npm run build mit relativen API-URLs (nginx-kompatibel).env \u2013 wird automatisch generiert (bei --reinstall bleibt bestehende erhalten)ripster:ripster auf Installationsverzeichnis, 600 auf .envripster-backend.service erstellt, aktiviert und gestartet/api/ und /ws (kann mit --no-nginx \u00fcbersprungen werden)# Status pr\u00fcfen\nsudo systemctl status ripster-backend\n\n# Logs verfolgen\nsudo journalctl -u ripster-backend -f\n\n# Neustart\nsudo systemctl restart ripster-backend\n\n# Aktualisieren\nsudo bash /opt/ripster/install.sh --reinstall\n Zugriff: http://<Maschinen-IP> (oder der mit --host angegebene Hostname)
Bei nicht-interaktiver Ausf\u00fchrung (Pipe von curl) wird automatisch die Standard-Version gew\u00e4hlt. F\u00fcr die GPU-Version zuerst herunterladen:
curl -fsSL https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh -o install.sh\nsudo bash install.sh\n# \u2192 Interaktive Auswahl: Option 2 f\u00fcr NVDEC\n Das geb\u00fcndelte Binary liegt unter bin/HandBrakeCLI und wird nach /usr/local/bin/HandBrakeCLI kopiert.
Die folgenden Abschnitte beschreiben die einzelnen Schritte f\u00fcr manuelle oder angepasste Setups.
"},{"location":"deployment/production/#empfohlene-architektur","title":"Empfohlene Architektur","text":"Client\n -> nginx (Reverse Proxy + statisches Frontend)\n -> Backend API/WebSocket (Node.js, Port 3001)\n Wichtig: Das Backend serviert im aktuellen Stand keine frontend/dist-Dateien automatisch.
cd frontend\nnpm install\nnpm run build\n Artefakte liegen in frontend/dist/.
Beispiel /etc/systemd/system/ripster-backend.service:
[Unit]\nDescription=Ripster Backend\nAfter=network.target\n\n[Service]\nType=simple\nUser=ripster\nWorkingDirectory=/opt/ripster/backend\nExecStart=/usr/bin/env node src/index.js\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\nEnvironment=PORT=3001\nEnvironment=LOG_LEVEL=info\n\n[Install]\nWantedBy=multi-user.target\n Aktivieren:
sudo systemctl daemon-reload\nsudo systemctl enable --now ripster-backend\nsudo systemctl status ripster-backend\n"},{"location":"deployment/production/#3-nginx-konfigurieren","title":"3) nginx konfigurieren","text":"Beispiel /etc/nginx/sites-available/ripster:
server {\n listen 80;\n server_name ripster.local;\n\n root /opt/ripster/frontend/dist;\n index index.html;\n\n location / {\n try_files $uri $uri/ /index.html;\n }\n\n location /api/ {\n proxy_pass http://127.0.0.1:3001;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n }\n\n location /ws {\n proxy_pass http://127.0.0.1:3001;\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n proxy_set_header Host $host;\n }\n}\n Aktivieren:
sudo ln -s /etc/nginx/sites-available/ripster /etc/nginx/sites-enabled/\nsudo nginx -t\nsudo systemctl reload nginx\n"},{"location":"deployment/production/#datenbank-backup","title":"Datenbank-Backup","text":"sqlite3 /opt/ripster/backend/data/ripster.db \\\n \".backup '/var/backups/ripster-$(date +%Y%m%d).db'\"\n"},{"location":"deployment/production/#sicherheit","title":"Sicherheit","text":".env, Settings-Felder).Dieses Kapitel ist f\u00fcr den Betrieb von Ripster im Alltag geschrieben.
"},{"location":"getting-started/#zielgruppe","title":"Zielgruppe","text":"Nach der Installation erfolgt die t\u00e4gliche Konfiguration fast vollst\u00e4ndig in der GUI unter Settings.
Vor dem ersten echten Job m\u00fcssen Pfade, Tools und Metadatenzugriff sauber gesetzt sein.
"},{"location":"getting-started/configuration/#reihenfolge-empfohlen","title":"Reihenfolge (empfohlen)","text":""},{"location":"getting-started/configuration/#1-settings-tab-konfiguration","title":"1.Settings -> Tab Konfiguration","text":"Setze zuerst diese Pflichtwerte:
Bereich Wichtige Felder Pfaderaw_dir, movie_dir, log_dir Tools makemkv_command, handbrake_command, mediainfo_command Metadaten omdb_api_key, optional omdb_default_type Danach \u00c4nderungen speichern.
Wenn du Blu-ray und DVD unterschiedlich behandeln willst, pflege die profilbezogenen Felder:
*_bluray*_dvd*_otherTypische Beispiele:
handbrake_preset_bluray und handbrake_preset_dvdraw_dir_bluray und raw_dir_dvdfilename_template_bluray und filename_template_dvdpipeline_max_parallel_jobs f\u00fcr parallele Jobshardware_monitoring_enabled und Intervall f\u00fcr Live-Metriken im DashboardIn den Benachrichtigungsfeldern setzen:
pushover_enabledpushover_tokenpushover_userDann \u00fcber PushOver Test direkt pr\u00fcfen.
Dashboard \u00f6ffnenAnalyse startenREADY_TO_ENCODE laufen lassenWenn diese Schritte funktionieren, ist die Grundkonfiguration korrekt.
"},{"location":"getting-started/configuration/#wenn-werte-nicht-gespeichert-werden","title":"Wenn Werte nicht gespeichert werden","text":"Die empfohlene Installation l\u00e4uft \u00fcber install.sh und richtet Ripster vollst\u00e4ndig ein.
systemd-Diensthttp://<Server-IP>wget -qO install.sh https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh\n"},{"location":"getting-started/installation/#2-installation-ausfuhren","title":"2. Installation ausf\u00fchren","text":"sudo bash install.sh\n W\u00e4hrend der Installation wirst du nach dem HandBrake-Modus gefragt:
1 Standard (apt)2 GPU/NVDEC (geb\u00fcndeltes Binary)sudo systemctl status ripster-backend\n"},{"location":"getting-started/installation/#4-weboberflache-offnen","title":"4. Weboberfl\u00e4che \u00f6ffnen","text":"http://<Server-IP>--no-nginx): API auf http://<Server-IP>:3001/api--branch <branch> anderen Branch installieren --dir <pfad> Installationsverzeichnis \u00e4ndern --port <port> Backend-Port setzen --host <hostname> Hostname/IP f\u00fcr nginx/CORS --no-makemkv MakeMKV nicht installieren --no-handbrake HandBrake nicht installieren --no-nginx nginx-Konfiguration \u00fcberspringen --reinstall Update einer bestehenden Installation Beispiele:
sudo bash install.sh --branch dev\nsudo bash install.sh --port 8080 --host ripster.local\nsudo bash install.sh --reinstall\n"},{"location":"getting-started/installation/#betrieb-im-alltag","title":"Betrieb im Alltag","text":"# Logs live ansehen\nsudo journalctl -u ripster-backend -f\n\n# Dienst neu starten\nsudo systemctl restart ripster-backend\n\n# Update aus bestehender Installation\nsudo bash /opt/ripster/install.sh --reinstall\n"},{"location":"getting-started/installation/#haufige-stolperstellen","title":"H\u00e4ufige Stolperstellen","text":"Permission denied am Laufwerk: Laufwerksrechte/Gruppen pr\u00fcfenmakemkvcon, HandBrakeCLI, mediainfo im PATH pr\u00fcfenDiese Seite ist die praktische Checkliste vor der Installation.
"},{"location":"getting-started/prerequisites/#1-system","title":"1) System","text":"Punkt Mindestwert Empfehlung Betriebssystem Linux oder macOS Ubuntu 22.04+ Node.js 20.19.0 20.x LTS RAM 4 GB 8 GB+ Freier Speicher 50 GB 500 GB+Node-Version pr\u00fcfen:
node --version\n"},{"location":"getting-started/prerequisites/#2-externe-tools","title":"2) Externe Tools","text":"Ripster ben\u00f6tigt folgende CLI-Tools im PATH:
makemkvconHandBrakeCLImediainfoSchnell pr\u00fcfen:
makemkvcon --version\nHandBrakeCLI --version\nmediainfo --Version\n"},{"location":"getting-started/prerequisites/#3-optisches-laufwerk","title":"3) Optisches Laufwerk","text":"F\u00fcr Disc-Betrieb muss ein DVD/Blu-ray-Laufwerk erreichbar sein.
ls /dev/sr*\nlsblk | grep rom\n Wenn n\u00f6tig Rechte setzen (Beispiel):
sudo chmod a+rw /dev/sr0\n"},{"location":"getting-started/prerequisites/#4-omdb-api-key","title":"4) OMDb API-Key","text":"F\u00fcr automatische Metadaten (Titel, Poster, IMDb-ID):
Settings als omdb_api_key eintragenF\u00fcr Push-Nachrichten bei Erfolg/Fehler:
pushover_token und pushover_user sp\u00e4ter in den Settings setzenmakemkvcon, HandBrakeCLI, mediainfo ausf\u00fchrbarDieser Ablauf zeigt einen vollst\u00e4ndigen Job aus Anwendersicht: von Disc-Erkennung bis fertiger Datei.
"},{"location":"getting-started/quickstart/#1-dashboard-offnen-und-disc-einlegen","title":"1. Dashboard \u00f6ffnen und Disc einlegen","text":"Erwartung:
DISC_DETECTED bzw. Medium erkanntDisk-Information sind Laufwerksdaten sichtbarWenn nichts passiert: Laufwerk neu lesen.
Aktion im Dashboard:
Analyse startenErwartung:
ANALYZINGIm Dialog Metadaten ausw\u00e4hlen:
Auswahl \u00fcbernehmenRIPPING -> MEDIAINFO_CHECK -> READY_TO_ENCODEMEDIAINFO_CHECK -> READY_TO_ENCODEWAITING_FOR_USER_DECISION (Playlist ausw\u00e4hlen und \u00fcbernehmen)READY_TO_ENCODE","text":"Im aufgeklappten Job (Pipeline-Status):
Dann Encoding starten.
W\u00e4hrend ENCODING:
Pipeline-StatusBei FINISHED:
Historie \u00f6ffnenHistorie -> OMDb neu zuordnenRAW neu encodierenReview neu startenRipster hat drei Hauptseiten in der Navigation plus eine Expert-Seite.
"},{"location":"gui/#seitenuberblick","title":"Seiten\u00fcberblick","text":"Seite Zweck Dashboard Live-Betrieb: Pipeline, Queue, Aktivit\u00e4ten, Disc-Infos Settings Konfiguration, Skripte, Ketten, Presets, Cronjobs Historie abgeschlossene/laufende Jobs durchsuchen und nachbearbeiten Database (Expert) tabellarische Rohsicht inkl. Orphan-RAW-Import"},{"location":"gui/#empfohlene-nutzung-im-alltag","title":"Empfohlene Nutzung im Alltag","text":"DashboardSettingsHistorieDatabaseDashboard, Settings, Historie sind direkt in der Kopfnavigation.Database ist als Expert-Route verf\u00fcgbar: /database.Das Dashboard ist die Betriebszentrale f\u00fcr laufende Jobs.
"},{"location":"gui/dashboard/#aufbau-der-seite","title":"Aufbau der Seite","text":"Die Bereiche erscheinen in dieser Reihenfolge:
Hardware MonitoringJob QueueSkript- / Cron-StatusJob \u00dcbersichtDisk-InformationZeigt live:
Wichtig f\u00fcr den Betrieb:
Settings aktivierbar/deaktivierbar (hardware_monitoring_*)Zwei Spalten:
Laufende JobsWarteschlangeM\u00f6gliche Aktionen:
X)+):Hinweis:
Parallel zeigt das aktuell konfigurierte Parallel-Limit (pipeline_max_parallel_jobs).Zeigt:
M\u00f6gliche Aktionen:
N\u00e4chster SchrittAbbrechenListe leerenKompakte Jobliste mit Status, Fortschritt, ETA. Klick auf einen Job klappt die Detailsteuerung auf.
Im aufgeklappten Zustand erscheint die Karte Pipeline-Status mit allen zustandsabh\u00e4ngigen Aktionen.
DISC_DETECTED / IDLE Analyse starten METADATA_SELECTION Metadaten \u00f6ffnen WAITING_FOR_USER_DECISION Playlist w\u00e4hlen und Playlist \u00fcbernehmen READY_TO_START Job starten READY_TO_ENCODE Tracks/Skripte pr\u00fcfen, dann Encoding starten laufend (ANALYZING/RIPPING/ENCODING) Abbrechen ERROR / CANCELLED Retry Rippen, Disk-Analyse neu starten Zus\u00e4tzlich je nach Job:
Review neu startenEncode neu startenAus Queue l\u00f6schenREADY_TO_ENCODE)","text":"Im selben Block siehst du:
Zeigt aktuelles Laufwerk und Disc-Metadaten (Pfad, Modell, Disc-Label, Mount).
Aktionen:
Laufwerk neu lesenDisk neu analysierenMetadaten-Modal \u00f6ffnenAuswahl \u00fcbernehmen startet den n\u00e4chsten Pipeline-SchrittNach Abbruch kann Ripster optional fragen, ob erzeugte RAW- oder Movie-Dateien gel\u00f6scht werden sollen.
"},{"location":"gui/dashboard/#queue-eintrag-einfugen","title":"Queue-Eintrag einf\u00fcgen","text":"Erstellt gezielt einen Skript-, Ketten- oder Warte-Eintrag an einer bestimmten Queue-Position.
"},{"location":"gui/database/","title":"Database (Expert)","text":"/database ist eine erweiterte Ansicht f\u00fcr Power-User und Recovery-F\u00e4lle.
/databaseHistorie & Datenbank","text":"Tabellarische Jobansicht mit:
Aktionen im Detaildialog entsprechen weitgehend der Seite Historie (inkl. Re-Encode, Review-Neustart, OMDb-Zuordnung, Dateil\u00f6schung).
RAW ohne Historie","text":"Listet RAW-Ordner, die keinen zugeh\u00f6rigen Job-Eintrag haben.
Aktionen:
RAW pr\u00fcfen (Scan der konfigurierten RAW-Pfade)Job anlegen (Orphan-RAW in Historie importieren)Diese Seite erlaubt Eingriffe mit direkter Auswirkung auf Datenbestand und Historie. Vor L\u00f6sch- oder Importaktionen Pfade und Zieljob sorgf\u00e4ltig pr\u00fcfen.
"},{"location":"gui/history/","title":"Historie","text":"Die Seite Historie ist f\u00fcr Suche, Pr\u00fcfung und Nachbearbeitung bestehender Jobs.
Filter und Werkzeuge:
Blu-ray, DVD, Sonstiges)Jeder Eintrag zeigt:
Klick auf einen Eintrag \u00f6ffnet die Detailansicht.
"},{"location":"gui/history/#job-detaildialog","title":"Job-Detaildialog","text":"Bereiche:
Tail, Vollst\u00e4ndig)OMDb neu zuordnenEncode neu startenReview neu startenRAW neu encodierenRAW l\u00f6schen, Movie l\u00f6schen, Beides l\u00f6schenHistorieneintrag l\u00f6schenAus Queue l\u00f6schenOMDb neu zuordnen mit gleicher best\u00e4tigter Auswahl neu encodieren Encode neu starten Titel-/Spurpr\u00fcfung komplett neu berechnen Review neu starten aus vorhandenem RAW erneut encodieren RAW neu encodieren Speicher freigeben Dateil\u00f6schaktionen"},{"location":"gui/history/#logs","title":"Logs","text":"Tail laden (800) f\u00fcr schnelle FehleranalyseVollst\u00e4ndiges Log laden f\u00fcr vollst\u00e4ndige NachverfolgungDie Seite Settings steuert Konfiguration und Automatisierung.
Konfiguration alle Kernsettings (Pfade, Tools, Monitoring, Metadaten, Queue, Benachrichtigungen) Scripte einzelne Bash-Skripte verwalten und testen Skriptketten Sequenzen aus Skript- und Warte-Schritten bauen Encode-Presets benutzerdefinierte Presets f\u00fcr das Review im Dashboard Cronjobs zeitgesteuerte Skript-/Kettenausf\u00fchrung"},{"location":"gui/settings/#tab-konfiguration","title":"Tab Konfiguration","text":"Wichtiges Bedienmuster:
\u00c4nderungen speichern\u00c4nderungen verwerfen oder Neu ladenZus\u00e4tzlich:
PushOver Test sendet eine TestnachrichtScripte","text":"Funktionen:
Test)Praxis:
Skriptketten","text":"Funktionen:
Im Ketten-Editor:
Warten, vorhandene Skripte)Encode-Presets","text":"Ein Preset b\u00fcndelt:
-Z)Universell, Blu-ray, DVD, Sonstiges)Verwendung:
READY_TO_ENCODE).Cronjobs","text":"Funktionen:
Jetzt ausf\u00fchrenAktiviert und Pushover toggelnHilfen:
crontab.guru im EditorKonfiguration sauber setzenDieser Abschnitt beschreibt die technische Pipeline-Logik hinter den UI-Workflows.
Workflow & Zust\u00e4nde
Zustandsmodell, \u00dcberg\u00e4nge, Queue-Verhalten.
Workflow
Encode-Planung
Aufbereitung von Titeln/Tracks und Best\u00e4tigungslogik.
Encoding
Playlist-Analyse
Bewertung mehrdeutiger Blu-ray-Playlists.
Playlist-Analyse
Pre-/Post-Encode-Ausf\u00fchrungen
Skript- und Kettenlauf vor/nach dem Encoding.
Encode-Skripte
Ripster erzeugt vor dem Encode einen encodePlan und l\u00e4sst ihn im Review-Panel best\u00e4tigen.
Quelle bestimmen (Disc/RAW)\n -> HandBrake-Scan (--scan --json)\n -> Plan erstellen (Titel, Audio, Untertitel)\n -> READY_TO_ENCODE\n -> Benutzer best\u00e4tigt Auswahl\n -> finaler HandBrake-Aufruf\n"},{"location":"pipeline/encoding/#review-inhalt-ready_to_encode","title":"Review-Inhalt (READY_TO_ENCODE)","text":"burnInforceddefaultTrackconfirm-encode)","text":"Typischer Payload:
{\n \"selectedEncodeTitleId\": 1,\n \"selectedTrackSelection\": {\n \"1\": {\n \"audioTrackIds\": [1, 2],\n \"subtitleTrackIds\": [3]\n }\n },\n \"selectedPreEncodeScriptIds\": [1],\n \"selectedPostEncodeScriptIds\": [2],\n \"selectedPreEncodeChainIds\": [3],\n \"selectedPostEncodeChainIds\": [4],\n \"selectedUserPresetId\": 5\n}\n Ripster speichert die best\u00e4tigte Auswahl in jobs.encode_plan_json und markiert encode_review_confirmed = 1.
Grundstruktur:
HandBrakeCLI \\\n -i <input> \\\n -o <output> \\\n -t <titleId> \\\n -Z \"<preset>\" \\\n <extra-args> \\\n -a <audioTrackIds|none> \\\n -s <subtitleTrackIds|none>\n Untertitel-Flags werden bei Bedarf erg\u00e4nzt:
--subtitle-burned=<id>--subtitle-default=<id>--subtitle-forced=<id> oder --subtitle-forcedVerhalten bei Fehlern:
ERROR beendet (Encode startet nicht)FINISHED bleiben, enth\u00e4lt aber Fehlerhinweis/Script-SummaryDer finale Outputpfad wird aus Settings-Templates aufgebaut.
Platzhalter:
${title}${year}${imdbId}Ung\u00fcltige Dateizeichen werden sanitisiert.
"},{"location":"pipeline/playlist-analysis/","title":"Playlist-Analyse","text":"Ripster analysiert bei Blu-ray-\u00e4hnlichen Quellen Playlists und fordert bei Mehrdeutigkeit eine manuelle Auswahl an.
"},{"location":"pipeline/playlist-analysis/#ziel","title":"Ziel","text":"Erkennen, welche Playlist wahrscheinlich der Hauptfilm ist, statt versehentlich eine Fake-/Dummy-Playlist zu verwenden.
"},{"location":"pipeline/playlist-analysis/#eingabedaten","title":"Eingabedaten","text":"Die Analyse basiert auf MakeMKV-Infos (u. a. Playlist-/Segment-Struktur, Laufzeiten, Titelzuordnung).
"},{"location":"pipeline/playlist-analysis/#auswertung-vereinfacht","title":"Auswertung (vereinfacht)","text":"F\u00fcr Kandidaten werden u. a. ber\u00fccksichtigt:
Daraus entstehen:
candidatesevaluatedCandidates (inkl. Score/Label)recommendationmanualDecisionRequiredWenn nach Filterung mehr als ein relevanter Kandidat \u00fcbrig bleibt, setzt Ripster manualDecisionRequired = true und wechselt auf:
WAITING_FOR_USER_DECISIONDann muss eine Playlist best\u00e4tigt werden, bevor der Workflow weiterl\u00e4uft.
"},{"location":"pipeline/playlist-analysis/#konfigurationseinfluss","title":"Konfigurationseinfluss","text":"Key Wirkungmakemkv_min_length_minutes Mindestlaufzeit f\u00fcr Kandidaten Default ist aktuell 60 Minuten.
Bei manueller Entscheidung zeigt das Dashboard Kandidaten inkl. Score/Bewertung und markiert eine Empfehlung.
Nach Best\u00e4tigung:
MEDIAINFO_CHECKREADY_TO_START/RIPPINGRipster kann Skripte und Skript-Ketten vor und nach dem Encode ausf\u00fchren.
"},{"location":"pipeline/post-encode-scripts/#ablauf","title":"Ablauf","text":"READY_TO_ENCODE\n -> Pre-Encode Skripte/Ketten\n -> HandBrake Encoding\n -> Post-Encode Skripte/Ketten\n -> FINISHED oder ERROR\n"},{"location":"pipeline/post-encode-scripts/#auswahl-im-review","title":"Auswahl im Review","text":"Im Review-Panel kannst du getrennt w\u00e4hlen:
selectedPreEncodeScriptIdsselectedPostEncodeScriptIdsselectedPreEncodeChainIdsselectedPostEncodeChainIdsERROR.FINISHED sein (mit Fehlerzusatz im Status/Log).Beim Script-Run werden gesetzt:
RIPSTER_SCRIPT_RUN_ATRIPSTER_JOB_IDRIPSTER_JOB_TITLERIPSTER_MODERIPSTER_INPUT_PATHRIPSTER_OUTPUT_PATHRIPSTER_RAW_PATHRIPSTER_SCRIPT_IDRIPSTER_SCRIPT_NAMERIPSTER_SCRIPT_SOURCEKetten unterst\u00fctzen zwei Step-Typen:
script (f\u00fchrt ein hinterlegtes Skript aus)wait (wartet waitSeconds)Bei Fehler in einem Script-Step wird die Kette abgebrochen.
"},{"location":"pipeline/post-encode-scripts/#testlaufe","title":"Testl\u00e4ufe","text":"POST /api/settings/scripts/:id/testPOST /api/settings/script-chains/:id/testErgebnisse enthalten Erfolg/Exit-Code, Laufzeit und stdout/stderr.
"},{"location":"pipeline/workflow/","title":"Workflow & Zust\u00e4nde","text":"Ripster steuert den Ablauf als State-Machine im pipelineService.
flowchart LR\n IDLE --> DISC_DETECTED\n DISC_DETECTED --> ANALYZING\n ANALYZING --> METADATA_SELECTION\n METADATA_SELECTION --> READY_TO_START\n READY_TO_START --> RIPPING\n READY_TO_START --> MEDIAINFO_CHECK\n MEDIAINFO_CHECK --> WAITING_FOR_USER_DECISION\n WAITING_FOR_USER_DECISION --> MEDIAINFO_CHECK\n MEDIAINFO_CHECK --> READY_TO_ENCODE\n READY_TO_ENCODE --> ENCODING\n ENCODING --> FINISHED\n ENCODING --> ERROR\n RIPPING --> ERROR\n RIPPING --> CANCELLED"},{"location":"pipeline/workflow/#state-liste","title":"State-Liste","text":"State Bedeutung IDLE Wartet auf Disc DISC_DETECTED Disc erkannt ANALYZING MakeMKV-Analyse l\u00e4uft METADATA_SELECTION Benutzer w\u00e4hlt Metadaten WAITING_FOR_USER_DECISION Playlist-Auswahl n\u00f6tig READY_TO_START \u00dcbergangszustand vor Start RIPPING MakeMKV-Rip l\u00e4uft MEDIAINFO_CHECK Quelle/Tracks werden ausgewertet READY_TO_ENCODE Review ist bereit ENCODING HandBrake l\u00e4uft FINISHED erfolgreich abgeschlossen CANCELLED abgebrochen ERROR fehlgeschlagen"},{"location":"pipeline/workflow/#typische-pfade","title":"Typische Pfade","text":""},{"location":"pipeline/workflow/#standardfall-kein-vorhandenes-raw","title":"Standardfall (kein vorhandenes RAW)","text":"RIPPINGMEDIAINFO_CHECKREADY_TO_ENCODEENCODINGFINISHEDREADY_TO_START springt direkt zu MEDIAINFO_CHECK (kein neuer Rip).
MEDIAINFO_CHECK -> WAITING_FOR_USER_DECISION bis Benutzer Playlist best\u00e4tigt.
Wenn pipeline_max_parallel_jobs erreicht ist:
script, chain, wait)cancel: laufenden Job abbrechen oder Queue-Eintrag entfernenretry: Fehler-/Abbruch-Job neu startenreencode: aus vorhandenem RAW neu encodierenrestart-review: Review aus RAW neu aufbauenrestart-encode: Encoding mit letzter best\u00e4tigter Auswahl neu startenRipster orchestriert externe CLI-Tools. Dieser Abschnitt erkl\u00e4rt deren Rolle im Gesamtsystem.
MakeMKV
Disc-Analyse und Ripping.
MakeMKV
HandBrake
Video-Encoding inklusive Preset-Logik.
HandBrake
MediaInfo
Track-/Containeranalyse f\u00fcr Review und Auswahl.
MediaInfo
Ripster verwendet HandBrakeCLI f\u00fcr Scan und Encode.
HandBrakeCLI --scan --json -i <input> -t 0\n"},{"location":"tools/handbrake/#encode-vereinfacht","title":"Encode (vereinfacht)","text":"HandBrakeCLI \\\n -i <input> \\\n -o <output> \\\n -t <titleId> \\\n -Z \"<preset>\" \\\n <extra-args> \\\n -a <audioTrackIds|none> \\\n -s <subtitleTrackIds|none>\n Optional erg\u00e4nzt Ripster:
--subtitle-burned=<id>--subtitle-default=<id>--subtitle-forced=<id> oder --subtitle-forcedRipster liest Presets mit:
HandBrakeCLI -z\n"},{"location":"tools/handbrake/#relevante-settings","title":"Relevante Settings","text":"Key Bedeutung handbrake_command CLI-Binary handbrake_preset_bluray / handbrake_preset_dvd profilspezifisches Preset handbrake_extra_args_bluray / handbrake_extra_args_dvd profilspezifische Zusatzargumente output_extension_bluray / output_extension_dvd Ausgabeformat handbrake_restart_delete_incomplete_output unvollst\u00e4ndige Ausgabe bei Neustart l\u00f6schen"},{"location":"tools/handbrake/#fortschritts-parsing","title":"Fortschritts-Parsing","text":"Ripster parst HandBrake-Stderr (Prozent/ETA/Detail) und sendet WebSocket-Progress (PIPELINE_PROGRESS).
HandBrakeCLI -z pr\u00fcfen--encoder-preset)Das Produktions-Installer-Script install.sh bietet eine Option zur Installation eines geb\u00fcndelten HandBrakeCLI-Binaries mit NVDEC-Unterst\u00fctzung (NVIDIA GPU-Dekodierung). Diese Option erscheint interaktiv w\u00e4hrend der Installation.
Ripster nutzt makemkvcon f\u00fcr Disc-Analyse und Rip.
makemkvcon -r info <source>\n <source> ist typischerweise:
disc:<index> (Auto-Modus)dev:/dev/sr0 (explicit)file:<path> (Datei/Ordner-Analyse)makemkvcon mkv <source> <title-or-all> <rawDir> [--minlength=...] [...extraArgs]\n"},{"location":"tools/makemkv/#rip-backup-modus","title":"Rip (Backup-Modus)","text":"makemkvcon backup <source> <rawDir> --decrypt\n"},{"location":"tools/makemkv/#registrierungsschlussel-optional","title":"Registrierungsschl\u00fcssel (optional)","text":"Wenn makemkv_registration_key gesetzt ist, f\u00fchrt Ripster vor Analyse/Rip aus:
makemkvcon reg <key>\n"},{"location":"tools/makemkv/#relevante-settings","title":"Relevante Settings","text":"Key Bedeutung makemkv_command CLI-Binary makemkv_source_index Source-Index im Auto-Modus makemkv_min_length_minutes Mindestlaufzeitfilter makemkv_rip_mode_bluray / makemkv_rip_mode_dvd mkv oder backup makemkv_analyze_extra_args_bluray / _dvd Zusatzargs Analyse makemkv_rip_extra_args_bluray / _dvd Zusatzargs Rip"},{"location":"tools/makemkv/#hinweise","title":"Hinweise","text":"makemkvInfo im Job gespeichert.Ripster nutzt mediainfo zur JSON-Analyse von Medien-Dateien.
mediainfo --Output=JSON <input>\n Der Input ist typischerweise eine RAW-Datei oder ein vom Workflow gew\u00e4hlter Inputpfad.
"},{"location":"tools/mediainfo/#verwendung-in-ripster","title":"Verwendung in Ripster","text":"mediainfoInfo im Jobmediainfo_command CLI-Binary mediainfo_extra_args_bluray / _dvd profilspezifische Zusatzargumente"},{"location":"tools/mediainfo/#troubleshooting","title":"Troubleshooting","text":"mediainfo --Output=JSON <datei>und (undetermined)Diese Seite beschreibt typische Abl\u00e4ufe mit den passenden UI-Aktionen.
"},{"location":"workflows/#workflow-1-standardlauf-disc-fertige-datei","title":"Workflow 1: Standardlauf (Disc -> fertige Datei)","text":"Dashboard: Disc einlegen, Analyse startenREADY_TO_ENCODE Titel/Tracks pr\u00fcfenEncoding startenHistorie kontrollierenWAITING_FOR_USER_DECISIONPipeline-Status Playlist-Kandidaten vergleichenPlaylist \u00fcbernehmenREADY_TO_ENCODESettings setzen (pipeline_max_parallel_jobs)Job QueueIn Historie -> Detaildialog:
OMDb neu zuordnenEncode neu startenReview neu startenRAW neu encodierenSettings -> Scripte: Skripte anlegen und testenSettings -> Skriptketten: Ketten bauen und testenSettings -> Cronjobs: zeitgesteuerte Ausf\u00fchrung konfigurierenSkript- / Cron-Status) \u00fcberwachenRetry Rippen oder Disk-Analyse neu startenREADY_TO_ENCODE, ist aber nicht aktive Session","text":"Historie oder Database: Im Dashboard \u00f6ffnen/database \u00f6ffnenRAW ohne HistorieJob anlegen