This commit is contained in:
2026-03-04 14:48:56 +00:00
parent 31d3e36597
commit 3b293bb743
11 changed files with 1116 additions and 310 deletions

View File

@@ -1,64 +1,221 @@
# Encode-Planung
# Encode-Planung & Track-Auswahl
`encodePlan.js` analysiert die MediaInfo-Ausgabe und erstellt einen strukturierten Encode-Plan mit Track-Auswahl.
`encodePlan.js` analysiert die HandBrake-Scan-Ausgabe, wählt Audio- und Untertitelspuren anhand von Regeln vor und erstellt einen vollständigen Encode-Plan für die Benutzer-Review.
---
## Ablauf
## Ablauf im Pipeline-Kontext
```
MediaInfo-JSON
Track-Parsing (Video, Audio, Untertitel)
Sprach-Normalisierung (ISO 639-1 → 639-3)
Codec-Klassifizierung (copy-kompatibel / transcode)
Encode-Plan generieren
Benutzer-Review im Frontend
HandBrake-CLI-Argumente aufbauen
RIPPING abgeschlossen (oder Pre-Rip-Scan)
HandBrake --scan (alle Titel & Tracks einlesen)
buildTrackSelectors() ← Regeln aus Einstellungen ableiten
selectTrackIds() ← Tracks anhand Regeln vorauswählen
resolveAudioEncoderAction() ← Encoder-Aktion pro Track bestimmen
buildDiscScanReview() ← Vollständigen Encode-Plan erstellen
READY_TO_ENCODE ← Benutzer-Review im Frontend
applyManualTrackSelectionToPlan() ← Benutzer-Auswahl anwenden
ENCODING ← HandBrake-CLI mit finalem Plan starten
```
---
## Encode-Plan-Format
## Phase 1: Pre-Rip Track-Scan
Der generierte Plan wird als JSON im Job-Datensatz gespeichert:
Ripster führt einen **HandBrake-Scan** bereits **vor dem eigentlichen Ripping** durch:
```bash
HandBrakeCLI --scan -i /dev/sr0 -t 0
```
Dieser Scan liest alle Titel und deren Tracks aus der Disc (ohne zu encodieren). So kann der Benutzer die Track-Auswahl bereits vor dem zeitintensiven Rip-Prozess bestätigen.
!!! info "Pre-Rip vs. Post-Rip"
Ob der Scan vor oder nach dem Ripping passiert, hängt vom konfigurierten Modus ab. Bei direktem Disc-Zugriff ist Pre-Rip möglich; nach einem MakeMKV-Backup wird die entstandene `.mkv`-Datei gescannt.
---
## Phase 2: Track-Selektor-Regeln (`buildTrackSelectors`)
Die Regeln werden aus den HandBrake-Einstellungen abgeleitet. Es gibt fünf **Selektionsmodi**:
| Modus | Beschreibung |
|------|-------------|
| `none` | Keine Tracks dieser Art übernehmen |
| `first` | Nur den ersten Track übernehmen |
| `all` | Alle Tracks übernehmen |
| `language` | Nur Tracks in bestimmten Sprachen |
| `explicit` | Bestimmte Track-IDs explizit angeben |
Der aktive Modus wird aus den `handbrake_*`-Einstellungen und `handbrake_extra_args` abgeleitet. Explizite CLI-Argumente (`--audio`, `--audio-lang-list`) überschreiben die Basis-Konfiguration.
---
## Phase 3: Automatische Vorauswahl (`selectTrackIds`)
### Audio-Tracks
```
Modus 'none' → Keine Audio-Tracks
Modus 'all' → Alle Tracks (oder nur erster, wenn firstOnly)
Modus 'language' → Alle Tracks in den konfigurierten Sprachen
Modus 'explicit' → Nur die angegebenen Track-IDs
Modus 'first' → Nur Track 1
```
Jeder Audio-Track erhält das Feld `selectedByRule: true/false` dieses zeigt dem Benutzer, welche Tracks automatisch vorausgewählt wurden.
**Sprach-Normalisierung (`normalizeLanguage`):**
Alle Sprachcodes werden auf **ISO 639-2** (3-Buchstaben) normalisiert:
| Eingabe | Normalisiert |
|--------|-------------|
| `de`, `ger` | `deu` |
| `German` | `deu` |
| `en`, `eng` | `eng` |
| `English` | `eng` |
| `fr`, `fre` | `fra` |
| `ja`, `jpn` | `jpn` |
| Unbekannt | `und` |
### Untertitel-Tracks
Gleiche Modus-Logik wie Audio, aber mit **zusätzlichen Flags** pro Track:
| Flag | Bedeutung |
|------|-----------|
| `burnIn` | Untertitel in Video einbrennen (`--subtitle-burned`) |
| `forced` | Nur erzwungene Untertitel übernehmen (`--subtitle-forced`) |
| `defaultTrack` | Als Standard-Untertitelspur markieren (`--subtitle-default`) |
Diese Flags werden im Encode-Review als Checkboxen angezeigt.
---
## Phase 4: Encoder-Aktion bestimmen (`resolveAudioEncoderAction`)
Für jeden vorausgewählten Audio-Track bestimmt Ripster die Encoder-Aktion:
```
Encoder-Einstellung Codec-Support in Copy-Mask? Aktion
─────────────────────────────────────────────────────────────────────
Kein Encoder / 'preset-default' → preset-default HandBrake-Preset entscheidet
encoder.startsWith('copy')
UND Codec in audioCopyMask → copy Direktkopie (verlustfrei)
UND Codec NICHT in audioCopyMask→ fallback Transcode mit Fallback-Encoder
sonstiger Encoder → transcode Transcode mit explizitem Encoder
```
**Encoder-Aktionstypen:**
| Typ | Label (UI) | Qualität |
|----|-----------|---------|
| `preset-default` | `Preset-Default (HandBrake)` | HandBrake entscheidet |
| `copy` | `Copy (ac3)` | Verlustfrei |
| `fallback` | `Fallback Transcode (av_aac)` | Mit Qualitätsverlust |
| `transcode` | `Transcode (av_aac)` | Mit Qualitätsverlust |
**Copy-kompatible Codecs (Standard Copy-Mask):**
| Codec | Encoder-String |
|-------|---------------|
| AC-3 | `copy:ac3` |
| E-AC-3 | `copy:eac3` |
| AAC | `copy:aac` |
| MP3 | `copy:mp3` |
| TrueHD | `copy:truehd` |
| DTS | `copy:dts` *(nur mit spez. HandBrake-Build)* |
| DTS-HD | `copy:dtshd` *(nur mit spez. HandBrake-Build)* |
!!! warning "DTS im Standard-HandBrake"
Standard-HandBrake-Builds unterstützen kein DTS-Passthrough. DTS-Tracks werden dann automatisch auf den Fallback-Encoder umgestellt (Standard: `av_aac`).
---
## Phase 5: Encode-Plan-Struktur
Der vollständige Plan wird im Job-Datensatz als `encode_plan_json` gespeichert:
```json
{
"inputFile": "/mnt/raw/Inception_t00.mkv",
"outputFile": "/mnt/movies/Inception (2010).mkv",
"preset": "H.265 MKV 1080p30",
"audioTracks": [
"mode": "pre_rip",
"preRip": true,
"encodeInputTitleId": 1,
"encodeInputPath": "disc-track-scan://title-1",
"selectors": {
"audio": { "mode": "language", "languages": ["deu", "eng"], "copyMask": ["copy:ac3", "copy:eac3"] },
"subtitle": { "mode": "none" }
},
"titles": [
{
"index": 1,
"codec": "dts",
"language": "deu",
"channels": 6,
"label": "Deutsch (DTS, 5.1)",
"copyCompatible": false,
"selected": true
},
{
"index": 2,
"codec": "truehd",
"language": "eng",
"channels": 8,
"label": "English (TrueHD, 7.1)",
"copyCompatible": true,
"selected": true
}
],
"subtitleTracks": [
{
"index": 1,
"language": "deu",
"label": "Deutsch",
"selected": true
"id": 1,
"fileName": "Disc Title 1",
"durationSeconds": 8885,
"selectedByMinLength": true,
"isEncodeInput": true,
"audioTracks": [
{
"id": 1,
"sourceTrackId": 1,
"language": "eng",
"languageLabel": "English",
"title": "5.1 Surround",
"format": "AC3",
"codecToken": "ac3",
"channels": "6",
"selectedByRule": true,
"selectedForEncode": true,
"encodePreviewActions": [
{ "type": "copy", "encoder": "copy:ac3", "label": "Copy (ac3)" }
],
"encodePreviewSummary": "Copy (ac3)"
},
{
"id": 2,
"sourceTrackId": 2,
"language": "deu",
"languageLabel": "Deutsch",
"format": "DTS",
"codecToken": "dts",
"channels": "6",
"selectedByRule": true,
"selectedForEncode": true,
"encodePreviewActions": [
{ "type": "fallback", "encoder": "av_aac", "label": "Fallback Transcode (av_aac)" }
],
"encodePreviewSummary": "Fallback Transcode (av_aac)"
},
{
"id": 3,
"language": "fra",
"languageLabel": "Français",
"selectedByRule": false,
"selectedForEncode": false,
"encodePreviewSummary": "Nicht übernommen"
}
],
"subtitleTracks": [
{
"id": 1,
"language": "deu",
"selectedByRule": true,
"selectedForEncode": true,
"burnIn": false,
"forced": false,
"defaultTrack": true,
"subtitlePreviewSummary": "Übernehmen",
"subtitlePreviewFlags": ["default"]
}
]
}
]
}
@@ -66,94 +223,107 @@ Der generierte Plan wird als JSON im Job-Datensatz gespeichert:
---
## Sprach-Normalisierung
## Phase 6: Benutzer-Review im Frontend (`MediaInfoReviewPanel`)
MediaInfo liefert Sprachcodes in verschiedenen Formaten. `encodePlan.js` normalisiert diese auf **ISO 639-3**:
Das Review-Panel zeigt:
| MediaInfo-Output | Normalisiert |
|----------------|-------------|
| `de` | `deu` |
| `German` | `deu` |
| `en` | `eng` |
| `English` | `eng` |
| `fr` | `fra` |
| `ja` | `jpn` |
```
┌─────────────────────────────────────────────────────────────────┐
│ Encode-Review Titel: Disc Title 1 │
│ Laufzeit: 2:28:05 │
├─────────────────────────────────────────────────────────────────┤
│ Audio-Spuren │
├──────┬──────────────────────────┬──────────────────────────────┤
│ [✓] │ Track 1: English (AC3) │ Copy (ac3) │
│ [✓] │ Track 2: Deutsch (DTS) │ Fallback Transcode (av_aac) │
│ [ ] │ Track 3: Français (DTS) │ Nicht übernommen │
├──────┴──────────────────────────┴──────────────────────────────┤
│ Untertitel-Spuren │
├──────┬──────────────────────────┬────────┬────────┬────────────┤
│ [✓] │ Track 1: Deutsch │Einbr.[ ]│Forced[ ]│Default[✓]│
│ [ ] │ Track 2: English │Einbr.[ ]│Forced[ ]│Default[ ]│
├──────┴──────────────────────────┴────────┴────────┴────────────┤
│ [Encode bestätigen] │
└─────────────────────────────────────────────────────────────────┘
```
Der Benutzer kann:
- **Audio-Tracks** per Checkbox aktivieren/deaktivieren
- **Untertitel-Flags** (Einbrennen, Forced, Default) setzen
- **Mehrere Titel** bei der Titleauswahl wechseln (für Discs mit mehreren Haupttiteln)
---
## Codec-Klassifizierung
## Phase 7: Benutzer-Auswahl anwenden (`applyManualTrackSelectionToPlan`)
HandBrake kann einige Codecs direkt kopieren (ohne Transcoding):
Nach "Encode bestätigen" wird die Benutzer-Auswahl auf den Plan angewendet:
| Codec | Copy-kompatibel | HandBrake-Encoder |
|-------|----------------|------------------|
| `ac3` | ✅ Ja | `copy:ac3` |
| `aac` | ✅ Ja | `copy:aac` |
| `mp3` | ✅ Ja | `copy:mp3` |
| `truehd` | ✅ Ja | `copy:truehd` |
| `eac3` | ✅ Ja | `copy:eac3` |
| `dts` | ❌ Nein | `ffaac` (transcode) |
| `dtshd` | ❌ Nein | `ffaac` (transcode) |
```json
Payload: {
"selectedEncodeTitleId": 1,
"selectedTrackSelection": {
"1": {
"audioTrackIds": [1, 2],
"subtitleTrackIds": [1]
}
}
}
```
!!! info "DTS-Transcoding"
HandBrake unterstützt kein DTS-Passthrough in den Standard-Builds. DTS-Tracks werden zu AAC transcodiert, es sei denn, du verwendest einen speziellen HandBrake-Build mit DTS-Unterstützung.
Jeder Track erhält `selectedForEncode: true/false` entsprechend der Auswahl. Die Encoder-Aktionen (`encodeActions`) der nicht gewählten Tracks werden geleert.
---
## HandBrake-CLI-Argumente
## Phase 8: HandBrake-CLI-Befehl
Aus dem Encode-Plan generiert `commandLine.js` die HandBrake-Argumente:
Aus dem finalisierten Plan baut Ripster den HandBrake-Aufruf:
```bash
HandBrakeCLI \
--input "/mnt/raw/Inception_t00.mkv" \
--output "/mnt/movies/Inception (2010).mkv" \
-i /dev/sr0 \
-o "/mnt/movies/Inception (2010).mkv" \
-t 1 \
--preset "H.265 MKV 1080p30" \
--audio 1,2 \
--aencoder copy:truehd,ffaac \
--subtitle 1 \
-a 1,2 \
-E copy:ac3,av_aac \
-s 1 \
--subtitle-default 1
```
### Zusätzliche Argumente
Über die Einstellung `handbrake_extra_args` können beliebige HandBrake-Argumente ergänzt werden:
```
--crop 0:0:0:0 --loose-anamorphic
```
| Argument | Quelle |
|---------|--------|
| `-i` | `encode_input_path` aus Job |
| `-o` | Ausgabepfad aus `filename_template` + `movie_dir` |
| `-t` | Gewählter Titel-Index |
| `-a` | Kommagetrennte Audio-Track-IDs der ausgewählten Tracks |
| `-E` | Kommagetrennte Encoder-Aktionen (eine pro Track, gleiche Reihenfolge wie `-a`) |
| `-s` | Kommagetrennte Untertitel-Track-IDs |
| `--subtitle-default` | Track-ID der als Default markierten Untertitelspur |
| `--preset` | `handbrake_preset`-Einstellung |
| Extras | `handbrake_extra_args`-Einstellung |
---
## Dateiname-Template
Die Ausgabedatei wird über das konfigurierte Template benannt:
| Platzhalter | Wert | Beispiel |
|------------|------|---------|
| `{title}` | Filmtitel von OMDb | `Inception` |
| `{year}` | Erscheinungsjahr | `2010` |
| `{imdb_id}` | IMDb-ID | `tt1375666` |
| `{type}` | `movie` oder `series` | `movie` |
```
Template: {title} ({year})
Ergebnis: Inception (2010).mkv
```
Verfügbare Platzhalter:
| Platzhalter | Wert |
|------------|------|
| `{title}` | Filmtitel von OMDb |
| `{year}` | Erscheinungsjahr |
| `{imdb_id}` | IMDb-ID (z.B. `tt1375666`) |
| `{type}` | `movie` oder `series` |
Sonderzeichen im Dateinamen werden automatisch sanitisiert (`:`, `/`, `?` etc. werden entfernt oder ersetzt).
Sonderzeichen (`:`, `/`, `?`, `*` etc.) werden automatisch aus dem Dateinamen entfernt.
---
## Re-Encoding
Abgeschlossene Jobs können mit geänderten Einstellungen neu encodiert werden:
Ein abgeschlossener Job kann ohne erneutes Ripping neu encodiert werden:
1. Job in der History auswählen
2. "Re-Encode" klicken
3. Neue Track-Auswahl treffen (oder bestehende übernehmen)
4. Encoding startet mit aktuellen Einstellungen
1. Job in der **History** öffnen
2. **"Re-Encode"** klicken
3. Track-Auswahl anpassen (oder bestehende übernehmen)
4. Encoding startet mit den aktuellen `handbrake_*`-Einstellungen
Dies ist nützlich, wenn sich das HandBrake-Preset oder die Track-Auswahl geändert hat, ohne die zeitintensive Ripping-Phase zu wiederholen.
Nützlich bei geänderten Presets, anderen Sprach-Präferenzen oder nach einem Einstellungs-Update.

View File

@@ -1,119 +1,209 @@
# Playlist-Analyse
Einige Blu-rays verwenden **Playlist-Obfuskierung** als Kopierschutz-Mechanismus. Ripster erkennt dieses Muster und hilft bei der Auswahl der korrekten Playlist.
Einige Blu-rays verwenden **Playlist-Obfuskierung** als Kopierschutz. Ripster analysiert automatisch alle MakeMKV-Titel und empfiehlt die korrekte Playlist auf Basis eines Segment-Scoring-Algorithmus aus `playlistAnalysis.js`.
---
## Das Problem: Playlist-Obfuskierung
Moderne Blu-rays können Hunderte von Playlists enthalten, von denen nur eine den eigentlichen Film enthält. Die anderen sind:
Moderne Blu-rays können Dutzende bis Hunderte von Titeln/Playlists enthalten. Der eigentliche Film steckt in genau einer davon alle anderen sind:
- **Kurze Dummy-Playlists** (wenige Sekunden bis Minuten)
- **Umgeordnete Segmente** (falsche Reihenfolge der Film-Segmente)
- **Duplizierte Inhalte** (mehrere Playlists mit gleichem Inhalt, verschiedenen Timestamps)
- **Kurze Dummy-Titel** (wenige Sekunden bis Minuten)
- **Titel mit verschachtelten Segmenten** (absichtlich versetzte Reihenfolge, sodass der Film falsch gerippt wird)
- **Titel gleicher Länge** (mehrere Playlists mit identischer Laufzeit, aber unterschiedlicher Segment-Reihenfolge)
Dies macht es schwierig, die korrekte Playlist manuell zu identifizieren.
Das Ziel der Obfuskierung: Ein einfacher Ripper wählt den erstbesten langen Titel und bekommt ein zerstückeltes, unbrauchbares Video.
---
## Ripsters Analyse-Algorithmus
## Wann wird die Analyse ausgelöst?
`playlistAnalysis.js` analysiert alle von MakeMKV erkannten Playlists nach mehreren Kriterien:
### 1. Laufzeit-Matching
Die erwartete Laufzeit (aus OMDb-Metadaten) wird mit der Playlist-Laufzeit verglichen:
Die Playlist-Analyse wird automatisch gestartet **sobald der Benutzer Metadaten bestätigt** (nach dem Metadaten-Dialog). Ripster ruft `makemkvcon` im Info-Modus auf und parst die TINFO-Ausgabe.
```
Filmtitel: Inception (2010)
OMDb-Laufzeit: 148 Minuten
Playlist 00800.mpls: 148:22 → ✅ Match
Playlist 00801.mpls: 1:23 → ❌ Zu kurz
Playlist 00900.mpls: 148:25 → ✅ Match (Duplikat?)
TINFO:<titleId>,26,"<segment-list>"
```
### 2. Titel-Ähnlichkeit
Playlists mit Namen, die dem Filmtitel ähneln, werden bevorzugt.
### 3. Segment-Validierung
Die Playlist-Segmente werden auf logische Reihenfolge geprüft.
### 4. Häufigkeits-Analyse
Bei mehreren Kandidaten: Welche Segment-Kombination kommt am häufigsten vor?
Feld **26** enthält die kommagetrennte Liste der Segment-Nummern in der Abspielreihenfolge des Titels.
---
## Benutzer-Interface
## Algorithmus im Detail (`playlistAnalysis.js`)
Wenn Playlist-Obfuskierung erkannt wird, zeigt Ripster im `MetadataSelectionDialog` eine Playlist-Auswahl:
### Schritt 1 Segment-Nummern parsen
```
┌─────────────────────────────────────────────────────┐
│ Playlist auswählen │
├─────────────────────────────────────────────────────┤
│ ★ 00800.mpls 2:28:05 ✓ Empfohlen (Laufzeit passt) │
│ 00801.mpls 0:01:23 Kurz (wahrscheinlich Menü) │
│ 00900.mpls 2:28:12 Mögliche Alternative │
│ 00901.mpls 0:00:45 Kurz │
│ ... ... ... │
├─────────────────────────────────────────────────────┤
│ Hinweis: 847 Playlists gefunden Analyse empfiehlt │
│ Playlist 00800.mpls als Hauptfilm. │
└─────────────────────────────────────────────────────┘
TINFO:1,26,"00000,00001,00002,00003" → [0, 1, 2, 3] linearer Film
TINFO:2,26,"00100,00050,00100,00051" → [100, 50, 100, 51] Fake-Playlist
```
### Schritt 2 Metriken berechnen (`computeSegmentMetrics`)
Für jedes aufeinanderfolgende Segment-Paar `[a, b]` wird `diff = b a` berechnet:
| Metrik | Bedingung | Bedeutung |
|--------|----------|-----------|
| `directSequenceSteps` | `diff == 1` | Aufeinanderfolgende Segmente → linearer Film |
| `backwardJumps` | `b < a` | Rückwärtssprünge → verdächtig |
| `largeJumps` | `\|diff\| > 20` | Große Sprünge → verdächtig |
| `alternatingPairs` | Große Sprünge mit **wechselndem Vorzeichen** | Hin-und-her-Muster → starker Fake-Indikator |
**Score-Formel:**
```
score = (directSequenceSteps × 2) (backwardJumps × 3) (largeJumps × 2)
```
**Konkrete Beispiele:**
| Segmentfolge | directSeq | backward | large | score | Ergebnis |
|-------------|-----------|----------|-------|-------|---------|
| `0,1,2,3,4,5` | 5 | 0 | 0 | +10 | Echter Film |
| `0,1,100,2,101,3` | 2 | 0 | 4 | -4 | Verdächtig |
| `50,10,60,11,70,12` | 0 | 3 | 3 | -15 | Fake |
### Schritt 3 Bewertungslabel vergeben (`buildEvaluationLabel`)
```
alternatingRatio = alternatingPairs / largeJumps
if alternatingRatio >= 0.55 AND alternatingPairs >= 3:
→ "Fake-Struktur (alternierendes Sprungmuster)"
else if backwardJumps > 0 OR largeJumps > 0:
→ "Auffällige Segmentreihenfolge"
else:
→ "wahrscheinlich korrekt (lineare Segmentfolge)"
```
### Schritt 4 Duplikat-Gruppen bilden (`buildSimilarityGroups`)
Alle Titel werden nach **ähnlicher Laufzeit** gruppiert (±90 Sekunden Toleranz). Gibt es mehrere Kandidaten mit ähnlicher Laufzeit, ist das ein klares Zeichen für Obfuskierung:
```
8 Titel mit ~148 Minuten Laufzeit → Duplikat-Gruppe
→ obfuscationDetected = true
→ manualDecisionRequired = true
```
### Schritt 5 Besten Kandidaten empfehlen (`scoreCandidates`)
Innerhalb der größten Duplikat-Gruppe werden alle Kandidaten sortiert nach:
1. `score` (höher = besser)
2. `sequenceCoherence` (Anteil linearer Segmentschritte)
3. Laufzeit (länger = besser)
4. Dateigröße (größer = besser als Tiebreaker)
Der **erste Kandidat** der sortierten Liste ist die Empfehlung.
---
## Analyse-Ergebnis-Format
## Wann greift der Benutzer ein?
```
obfuscationDetected = duplicateDurationGroups.length > 0
manualDecisionRequired = obfuscationDetected
```
| Ergebnis | Nächster Pipeline-Zustand | Aktion |
|---------|--------------------------|--------|
| Keine Duplikat-Gruppen | `READY_TO_START` | Empfehlung wird automatisch übernommen |
| Duplikat-Gruppen gefunden | `WAITING_FOR_USER_DECISION` | Benutzer muss Playlist auswählen |
---
## Benutzeroberfläche: Playlist-Auswahl-Dialog
Wenn `manualDecisionRequired = true`, öffnet sich der Playlist-Dialog **nach** dem Metadaten-Dialog:
```
┌───────────────────────────────────────────────────────────────────┐
│ Playlist-Auswahl │
├──────────┬──────────┬──────────┬────────────────────────────────┤
│ Playlist │ Laufzeit │ Score │ Bewertung │
├──────────┼──────────┼──────────┼────────────────────────────────┤
│ ★ 00800 │ 2:28:05 │ +18 │ wahrscheinlich korrekt │
│ │ │ │ (lineare Segmentfolge) │
├──────────┼──────────┼──────────┼────────────────────────────────┤
│ 00801 │ 2:28:12 │ 4 │ Auffällige Segmentreihenfolge │
├──────────┼──────────┼──────────┼────────────────────────────────┤
│ 00900 │ 2:28:05 │ 32 │ Fake-Struktur │
│ │ │ │ (alternierendes Sprungmuster) │
└──────────┴──────────┴──────────┴────────────────────────────────┘
Hinweis: 847 Playlists insgesamt. 3 relevante Kandidaten (≥ 15 min).
Empfehlung: 00800 (★)
```
- **★** markiert die empfohlene Playlist (vorausgewählt)
- Nur Titel ≥ `makemkv_min_length_minutes` erscheinen in der Liste
- Der Benutzer wählt per Radio-Button und klickt "Bestätigen"
- Erst nach dieser Bestätigung wechselt die Pipeline zu `READY_TO_START`
---
## Vollständige Datenstruktur (`analyzeContext.playlistAnalysis`)
```json
{
"titles": [
{ "titleId": 1, "playlistId": "00800", "durationSeconds": 8885, "durationLabel": "2:28:05", "chapters": 28 }
],
"candidates": [
{ "titleId": 1, "playlistId": "00800", "durationSeconds": 8885 },
{ "titleId": 2, "playlistId": "00801", "durationSeconds": 8892 }
],
"evaluatedCandidates": [
{
"playlist": "00800.mpls",
"duration": "2:28:05",
"durationSeconds": 8885,
"score": 0.95,
"recommended": true,
"reasons": ["Laufzeit stimmt mit OMDb überein", "Häufigste Segment-Kombination"]
},
{
"playlist": "00900.mpls",
"duration": "2:28:12",
"durationSeconds": 8892,
"score": 0.72,
"recommended": false,
"reasons": ["Ähnliche Laufzeit", "Seltene Segment-Kombination"]
"titleId": 1,
"playlistId": "00800",
"score": 18,
"sequenceCoherence": 0.95,
"evaluationLabel": "wahrscheinlich korrekt (lineare Segmentfolge)",
"metrics": {
"directSequenceSteps": 12,
"backwardJumps": 0,
"largeJumps": 1,
"alternatingPairs": 0
}
}
],
"totalPlaylists": 847,
"recommendation": "00800.mpls"
"duplicateDurationGroups": [
[
{ "titleId": 1, "playlistId": "00800" },
{ "titleId": 2, "playlistId": "00801" }
]
],
"recommendation": {
"titleId": 1,
"playlistId": "00800",
"score": 18,
"reason": "Höchster Segment-Score in der größten Laufzeit-Gruppe"
},
"obfuscationDetected": true,
"manualDecisionRequired": true
}
```
---
## Manuelle Auswahl
## Konfiguration
Falls die automatische Empfehlung nicht korrekt ist:
1. Wähle eine andere Playlist aus der Liste
2. Beachte die Laufzeit-Angabe
3. Vergleiche mit der erwarteten Filmlänge (aus OMDb oder Disc-Hülle)
!!! tip "Tipp"
Bei Blu-rays von bekannten Filmen kannst du die korrekte Playlist oft über Foren wie [MakeMKV-Forum](https://www.makemkv.com/forum/) verifizieren.
| Einstellung | Standard | Wirkung |
|------------|---------|---------|
| `makemkv_min_length_minutes` | `15` | Titel kürzer als dieser Wert werden als Kandidaten ignoriert |
---
## Konfiguration
## Tipps bei Fehlempfehlung
Die Playlist-Analyse ist automatisch aktiv. Einstellbar ist:
!!! tip "Falsche Playlist gewählt?"
Wenn das resultierende Video zerstückelt ist:
| Parameter | Beschreibung |
|----------|-------------|
| `makemkv_min_length_minutes` | Mindestlänge, um als Hauptfilm-Kandidat zu gelten (Standard: 15 Min) |
1. Job in der **History** öffnen
2. **Re-Encode** starten diesmal eine andere Playlist wählen
3. Alternativ: Korrekte Playlist im [MakeMKV-Forum](https://www.makemkv.com/forum/) recherchieren
!!! info "Keine Segment-Daten verfügbar"
Bei DVDs oder älteren Blu-rays liefert MakeMKV manchmal keine Segmentinfos (TINFO-Feld 26 fehlt). In diesem Fall entfällt die Analyse und der erste Titel über der Mindestlänge wird automatisch verwendet.