{"config":{"lang":["de"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Ripster","text":"
Halbautomatische Disc-Ripping-Plattform f\u00fcr DVDs und Blu-rays
Automatisiertes Ripping
Disc einlegen \u2013 Ripster erkennt sie automatisch und startet den Analyse-Workflow mit MakeMKV.
Workflow verstehen
Metadata-Integration
Automatische Suche in der OMDb-Datenbank f\u00fcr Filmtitel, Poster und IMDb-IDs.
Konfiguration
Flexibles Encoding
HandBrake-Encoding mit individueller Track-Auswahl f\u00fcr Audio- und Untertitelspuren.
Encode-Planung
Job-Historie
Vollst\u00e4ndiges Audit-Trail aller Ripping-Jobs mit Logs und Re-Encode-Funktion.
History API
Ripster ist eine webbasierte Anwendung zur halbautomatischen Digitalisierung von DVDs und Blu-rays. Die Anwendung kombiniert bew\u00e4hrte Open-Source-Tools zu einem durchg\u00e4ngigen, komfortablen Workflow:
Disc einlegen \u2192 Erkennung \u2192 Analyse \u2192 Metadaten w\u00e4hlen \u2192 Rippen \u2192 Encodieren \u2192 Fertig\n"},{"location":"#kernfunktionen","title":"Kernfunktionen","text":"Feature Beschreibung Echtzeit-Updates WebSocket-basierte Live-Statusanzeige ohne Reload Intelligente Playlist-Analyse Erkennt Blu-ray Playlist-Verschleierung (Fake-Playlists) Track-Auswahl Individuelle Auswahl von Audio- und Untertitelspuren Orphan-Recovery Import von bereits gerippten Dateien als Jobs PushOver-Benachrichtigungen Mobile Alerts bei Fertigstellung oder Fehlern DB-Korruptions-Recovery Automatische Quarant\u00e4ne bei korrupten SQLite-Dateien Re-Encoding Erneutes Encodieren ohne neu rippen"},{"location":"#technologie-stack","title":"Technologie-Stack","text":"BackendFrontendExterne Tools ws) f\u00fcr Echtzeit-Kommunikationmakemkvcon, HandBrakeCLI, mediainfomakemkvcon Disc-Analyse & MKV/Backup-Ripping HandBrakeCLI Video-Encoding mediainfo Track-Informationen aus gerippten Dateien OMDb API Filmmetadaten (Titel, Poster, IMDb-ID)"},{"location":"#schnellstart","title":"Schnellstart","text":"# 1. Repository klonen\ngit clone https://github.com/YOUR_GITHUB_USERNAME/ripster.git\ncd ripster\n\n# 2. Starten (Node.js >= 20 erforderlich)\n./start.sh\n\n# 3. Browser \u00f6ffnen\nopen http://localhost:5173\n Erste Schritte
Die vollst\u00e4ndige Installationsanleitung mit allen Voraussetzungen findest du unter Erste Schritte.
"},{"location":"#pipeline-uberblick","title":"Pipeline-\u00dcberblick","text":"flowchart LR\n IDLE --> DD[DISC_DETECTED]\n DD --> META[METADATA\\nSELECTION]\n META --> RTS[READY_TO\\nSTART]\n RTS -->|Auto-Start| RIP[RIPPING]\n RTS -->|Auto-Start mit RAW| MIC\n RIP --> MIC[MEDIAINFO\\nCHECK]\n MIC -->|Playlist offen (Backup)| WUD[WAITING_FOR\\nUSER_DECISION]\n WUD --> MIC\n MIC --> RTE[READY_TO\\nENCODE]\n RTE --> ENC[ENCODING]\n ENC -->|inkl. Post-Skripte| FIN([FINISHED])\n ENC --> ERR([ERROR])\n RIP --> ERR\n\n style FIN fill:#e8f5e9,stroke:#66bb6a,color:#2e7d32\n style ERR fill:#ffebee,stroke:#ef5350,color:#c62828\n style WUD fill:#fff8e1,stroke:#ffa726,color:#e65100\n style ENC fill:#f3e5f5,stroke:#ab47bc,color:#6a1b9a READY_TO_START ist in der Praxis meist ein kurzer \u00dcbergangszustand: der Job wird nach Metadaten-Auswahl automatisch gestartet oder in die Queue eingeplant.
Ripster bietet eine REST-API f\u00fcr Steuerung/Verwaltung sowie einen WebSocket-Endpunkt f\u00fcr Echtzeit-Updates.
"},{"location":"api/#basis-url","title":"Basis-URL","text":"http://localhost:3001\n API-Prefix: /api
Beispiele:
GET /api/healthGET /api/pipeline/stateHealth
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
Es gibt keine eingebaute Authentifizierung. Ripster ist f\u00fcr lokalen Betrieb gedacht.
"},{"location":"api/#fehlerformat","title":"Fehlerformat","text":"Fehler werden zentral als JSON geliefert:
{\n \"error\": {\n \"message\": \"Job nicht gefunden.\",\n \"statusCode\": 404,\n \"reqId\": \"req_...\",\n \"details\": [\n {\n \"field\": \"name\",\n \"message\": \"Name darf nicht leer sein.\"\n }\n ]\n }\n}\n details ist optional (z. B. bei Validierungsfehlern).
200 Erfolg 201 Ressource erstellt 400 Ung\u00fcltige Anfrage / Validierungsfehler 404 Ressource nicht gefunden 409 Konflikt (z. B. falscher Pipeline-Zustand, Job l\u00e4uft bereits) 500 Interner Fehler"},{"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/settings/","title":"Settings API","text":"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/#reconnect-verhalten","title":"Reconnect-Verhalten","text":"useWebSocket verbindet bei Abbruch automatisch neu:
1500msRipster ist eine Client-Server-Anwendung mit REST + WebSocket.
"},{"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/#schichten","title":"Schichten","text":""},{"location":"architecture/#backend","title":"Backend","text":"src/index.js (Bootstrapping, Routes, WS, Services)src/routes/* (Pipeline, Settings, History, Crons)src/services/* (Business-Logik)src/db/database.js (Init/Migration)src/utils/* (Parser, Dateifunktionen, Validierung)App.jsx + pages/* (Dashboard, Settings, History)components/* (Status-/Review-/Dialog-Komponenten)api/client.js (REST-Client)hooks/useWebSocket.js (WS-Reconnect)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_UPDATEDscriptService.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 konfigurierbarEinstellungsreferenz
Alle verf\u00fcgbaren Einstellungen mit Typen, Standardwerten und Beschreibungen.
Einstellungsreferenz
Umgebungsvariablen
Umgebungsvariablen f\u00fcr Backend und Frontend.
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_detectedEntwicklungsumgebung
Lokale Entwicklungsumgebung einrichten.
Entwicklung
Produktion
Ripster auf einem Server dauerhaft betreiben.
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/development/#deploy-script-optional","title":"Deploy-Script (optional)","text":"deploy-ripster.sh synchronisiert den lokalen Stand auf einen Remote-Host per rsync/SSH und sch\u00fctzt backend/data.
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).Dieser Abschnitt f\u00fchrt dich durch die Installation und Einrichtung von Ripster.
"},{"location":"getting-started/#uberblick","title":"\u00dcberblick","text":":material-list-check: Voraussetzungen
Systemanforderungen und externe Tools, die vor der Installation ben\u00f6tigt werden.
Voraussetzungen pr\u00fcfen
Installation
Schritt-f\u00fcr-Schritt-Anleitung zur Installation von Ripster.
Installation starten
Konfiguration
Einrichten von Pfaden, API-Keys und Encoding-Presets.
Konfigurieren
Schnellstart
Rippe deinen ersten Film in wenigen Minuten.
Loslegen
Die Hauptkonfiguration erfolgt \u00fcber die UI (Settings) und wird in SQLite gespeichert.
raw_dir Basisverzeichnis f\u00fcr RAW-Rips /mnt/ripster/raw movie_dir Basisverzeichnis f\u00fcr finale Encodes /mnt/ripster/movies log_dir Verzeichnis f\u00fcr Prozess-/Backend-Logs /mnt/ripster/logs Optional profilspezifisch:
raw_dir_bluray, raw_dir_dvd, raw_dir_othermovie_dir_bluray, movie_dir_dvd, movie_dir_othermakemkv_command makemkvcon handbrake_command HandBrakeCLI mediainfo_command mediainfo"},{"location":"getting-started/configuration/#3-omdb","title":"3) OMDb","text":"Einstellung Beschreibung omdb_api_key API-Key von omdbapi.com omdb_default_type movie, series, episode"},{"location":"getting-started/configuration/#encode-konfiguration-wichtig","title":"Encode-Konfiguration (wichtig)","text":"Ripster arbeitet profilspezifisch, typischerweise \u00fcber:
handbrake_preset_bluray, handbrake_extra_args_bluray, output_extension_bluray, filename_template_blurayhandbrake_preset_dvd, handbrake_extra_args_dvd, output_extension_dvd, filename_template_dvdVerf\u00fcgbar in filename_template_* und output_folder_template_*:
${title}${year}${imdbId}Beispiel:
${title} (${year})\n-> Inception (2010).mkv\n"},{"location":"getting-started/configuration/#makemkv-spezifisch","title":"MakeMKV-spezifisch","text":"Einstellung Standard Hinweis makemkv_min_length_minutes 60 Kandidaten-Filter makemkv_rip_mode_bluray backup mkv oder backup makemkv_rip_mode_dvd mkv mkv oder backup makemkv_registration_key leer optional, wird via makemkvcon reg gesetzt"},{"location":"getting-started/configuration/#monitoring-queue","title":"Monitoring & Queue","text":"Einstellung Standard hardware_monitoring_enabled true hardware_monitoring_interval_ms 5000 pipeline_max_parallel_jobs 1"},{"location":"getting-started/configuration/#pushover-optional","title":"PushOver (optional)","text":"Basis:
pushover_enabledpushover_tokenpushover_userZus\u00e4tzlich pro Event ein/aus (z. B. pushover_notify_job_finished).
git clone https://github.com/YOUR_GITHUB_USERNAME/ripster.git\ncd ripster\n"},{"location":"getting-started/installation/#dev-start-empfohlen","title":"Dev-Start (empfohlen)","text":"./start.sh\n start.sh:
>= 20.19.0)Danach:
http://localhost:3001http://localhost:5173Stoppen: mit Ctrl+C im laufenden Terminal.
npm install\nnpm --prefix backend install\nnpm --prefix frontend install\nnpm run dev\n Oder getrennt:
npm run dev:backend\nnpm run dev:frontend\n"},{"location":"getting-started/installation/#optional-env-dateien-anlegen","title":"Optional: .env-Dateien anlegen","text":""},{"location":"getting-started/installation/#backend","title":"Backend","text":"cp backend/.env.example backend/.env\n Beispiel:
PORT=3001\nDB_PATH=./data/ripster.db\nLOG_DIR=./logs\nCORS_ORIGIN=http://localhost:5173\nLOG_LEVEL=info\n"},{"location":"getting-started/installation/#frontend","title":"Frontend","text":"cp frontend/.env.example frontend/.env\n Beispiel:
VITE_API_BASE=/api\n# optional:\n# VITE_WS_URL=ws://localhost:3001/ws\n"},{"location":"getting-started/installation/#datenbank","title":"Datenbank","text":"SQLite wird automatisch beim Backend-Start initialisiert:
backend/data/ripster.db\n Schema-Quelle: db/schema.sql
http://localhost:5173Settings Pfade/Tools/API-Keys pr\u00fcfenBevor du Ripster installierst, stelle sicher, dass folgende Software auf deinem System verf\u00fcgbar ist.
"},{"location":"getting-started/prerequisites/#system-anforderungen","title":"System-Anforderungen","text":"Anforderung Mindestversion Empfohlen Betriebssystem Linux / macOS Ubuntu 22.04+ Node.js 20.19.0 20.x LTS RAM 4 GB 8 GB+ Festplatte 50 GB frei 500 GB+ (f\u00fcr Roh-MKVs)"},{"location":"getting-started/prerequisites/#nodejs","title":"Node.js","text":"Ripster ben\u00f6tigt Node.js >= 20.19.0.
nvm (empfohlen)Ubuntu/DebianmacOS (Homebrew)# nvm installieren\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\n\n# Node.js 20 installieren\nnvm install 20\nnvm use 20\n\n# Version pr\u00fcfen\nnode --version # v20.x.x\n curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -\nsudo apt-get install -y nodejs\n\nnode --version # v20.x.x\n brew install node@20\nnode --version # v20.x.x\n"},{"location":"getting-started/prerequisites/#externe-tools","title":"Externe Tools","text":""},{"location":"getting-started/prerequisites/#makemkv","title":"MakeMKV","text":"Lizenz erforderlich
MakeMKV ist f\u00fcr den pers\u00f6nlichen Gebrauch kostenlos (Beta-Lizenz), ben\u00f6tigt aber eine g\u00fcltige Lizenz.
# Ubuntu/Debian - PPA verwenden\nsudo add-apt-repository ppa:heyarje/makemkv-beta\nsudo apt-get update\nsudo apt-get install makemkv-bin makemkv-oss\n\n# Installierte Version pr\u00fcfen\nmakemkvcon --version\n MakeMKV Download
"},{"location":"getting-started/prerequisites/#handbrake-cli","title":"HandBrake CLI","text":"# Ubuntu/Debian\nsudo add-apt-repository ppa:stebbins/handbrake-releases\nsudo apt-get update\nsudo apt-get install handbrake-cli\n\n# Version pr\u00fcfen\nHandBrakeCLI --version\n\n# macOS\nbrew install handbrake\n HandBrake Download
"},{"location":"getting-started/prerequisites/#mediainfo","title":"MediaInfo","text":"# Ubuntu/Debian\nsudo apt-get install mediainfo\n\n# macOS\nbrew install mediainfo\n\n# Version pr\u00fcfen\nmediainfo --Version\n"},{"location":"getting-started/prerequisites/#disc-laufwerk","title":"Disc-Laufwerk","text":"Ripster ben\u00f6tigt ein physisches DVD- oder Blu-ray-Laufwerk.
LibDriveIO-Modus erforderlich
Das Laufwerk muss im LibDriveIO-Modus betrieben werden \u2013 MakeMKV greift direkt auf Rohdaten des Laufwerks zu. Ohne diesen Modus k\u00f6nnen verschl\u00fcsselte Blu-rays (insbesondere UHD) nicht gelesen werden.
Nicht alle Laufwerke unterst\u00fctzen den direkten Zugriff. Eine Anleitung zur Einrichtung und Liste kompatibler Laufwerke findet sich im MakeMKV-Forum.
# Laufwerk pr\u00fcfen\nls /dev/sr*\n# oder\nlsblk | grep rom\n\n# Laufwerk-Berechtigungen setzen (erforderlich f\u00fcr LibDriveIO)\nsudo chmod a+rw /dev/sr0\n Blu-ray unter Linux
MakeMKV bringt mit LibDriveIO eine eigene Entschl\u00fcsselung mit \u2013 externe Bibliotheken wie libaacs sind in der Regel nicht erforderlich.
Ripster verwendet die OMDb API f\u00fcr Filmmetadaten.
F\u00fcr mobile Push-Benachrichtigungen bei Fertigstellung oder Fehlern:
F\u00fcr Remote-Deployment via deploy-ripster.sh:
# sshpass installieren\nsudo apt-get install sshpass\n"},{"location":"getting-started/prerequisites/#checkliste","title":"Checkliste","text":"node --version)makemkvcon installiert (makemkvcon --version)HandBrakeCLI installiert (HandBrakeCLI --version)mediainfo installiert (mediainfo --Version)ls /dev/sr*)Diese Seite f\u00fchrt durch den typischen ersten Lauf.
"},{"location":"getting-started/quickstart/#1-starten","title":"1) Starten","text":"cd ripster\n./start.sh\n \u00d6ffne http://localhost:5173.
Pipeline wechselt auf DISC_DETECTED.
Falls n\u00f6tig manuell neu scannen:
curl -X POST http://localhost:3001/api/pipeline/rescan-disc\n"},{"location":"getting-started/quickstart/#3-analyse-starten","title":"3) Analyse starten","text":"Klicke im Dashboard auf Analyse starten.
Intern:
ANALYZING)METADATA_SELECTION)Im Dialog:
selectedPlaylist w\u00e4hlenNach Best\u00e4tigung startet Ripster automatisch weiter.
"},{"location":"getting-started/quickstart/#5-pipeline-pfade","title":"5) Pipeline-Pfade","text":"Abh\u00e4ngig von Job/RAW-Situation:
RIPPINGMEDIAINFO_CHECKWAITING_FOR_USER_DECISIONWenn Parallel-Limit erreicht ist, wird der Job in die Queue eingereiht.
"},{"location":"getting-started/quickstart/#6-review-ready_to_encode","title":"6) Review (READY_TO_ENCODE)","text":"Im Review-Panel:
Mit Encoding starten wird confirm-encode + Start ausgel\u00f6st.
ENCODING)","text":"W\u00e4hrend Encoding:
Wichtig:
ERRORFINISHED bleiben, aber mit Fehlerhinweis im Status/LogFINISHED)","text":"Ergebnis:
movie_dir (ggf. profilspezifisch)log_dir# Pipeline-Snapshot\ncurl http://localhost:3001/api/pipeline/state\n\n# Queue-Snapshot\ncurl http://localhost:3001/api/pipeline/queue\n\n# Jobs\ncurl http://localhost:3001/api/history\n"},{"location":"pipeline/","title":"Pipeline","text":"Der Pipeline-Bereich beschreibt den Kern-Workflow von Ripster.
Workflow & Zust\u00e4nde
Zust\u00e4nde, \u00dcberg\u00e4nge und Queue-Verhalten.
Workflow
Encode-Planung
Wie Titel/Tracks f\u00fcr HandBrake vorbereitet und best\u00e4tigt werden.
Encoding
Playlist-Analyse
Bewertung mehrdeutiger Blu-ray-Playlists und manuelle Entscheidung.
Playlist-Analyse
Encode-Skripte (Pre & Post)
Skripte/Ketten vor und nach dem Encode ausf\u00fchren.
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 ist ein Orchestrator \u2013 die eigentliche Arbeit erledigen diese bew\u00e4hrten Open-Source-Tools:
MakeMKV
Disc-Analyse und Ripping. Erstellt MKV-Dateien oder vollst\u00e4ndige Backups.
MakeMKV
HandBrake
Video-Encoding mit umfangreichen Preset-Optionen.
HandBrake
MediaInfo
Analyse von Track-Informationen in Mediendateien.
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)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)