Files
ripster/docs/pipeline/playlist-analysis.md

218 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Playlist-Analyse
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 Dutzende bis Hunderte von Titeln/Playlists enthalten. Der eigentliche Film steckt in genau einer davon alle anderen sind:
- **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)
Das Ziel der Obfuskierung: Ein einfacher Ripper wählt den erstbesten langen Titel und bekommt ein zerstückeltes, unbrauchbares Video.
---
## Wann wird die Analyse ausgelöst?
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.
```
TINFO:<titleId>,26,"<segment-list>"
```
Feld **26** enthält die kommagetrennte Liste der Segment-Nummern in der Abspielreihenfolge des Titels.
---
## Algorithmus im Detail (`playlistAnalysis.js`)
### Schritt 1 Segment-Nummern parsen
```
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
```
### 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.
### Schritt 6 Entscheidung erzwingen bei mehreren Kandidaten
Sobald nach `MIN_LENGTH_MINUTES` **mehr als eine** Playlist übrig bleibt, wird immer eine manuelle Auswahl verlangt:
```
candidateCount > 1 → manualDecisionRequired = true
candidateCount <= 1 → manualDecisionRequired = false
```
---
## Wann greift der Benutzer ein?
```
obfuscationDetected = duplicateDurationGroups.length > 0
manualDecisionRequired = candidates.length > 1
```
| Ergebnis | Nächster Pipeline-Zustand | Aktion |
|---------|--------------------------|--------|
| Nur ein Kandidat nach Mindestlänge | `READY_TO_START` | Automatische Übernahme möglich |
| Mehrere Kandidaten nach Mindestlänge | `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": [
{
"titleId": 1,
"playlistId": "00800",
"score": 18,
"sequenceCoherence": 0.95,
"evaluationLabel": "wahrscheinlich korrekt (lineare Segmentfolge)",
"metrics": {
"directSequenceSteps": 12,
"backwardJumps": 0,
"largeJumps": 1,
"alternatingPairs": 0
}
}
],
"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
}
```
---
## Konfiguration
| Einstellung | Standard | Wirkung |
|------------|---------|---------|
| `makemkv_min_length_minutes` | `15` | Titel kürzer als dieser Wert werden als Kandidaten ignoriert |
---
## Tipps bei Fehlempfehlung
!!! tip "Falsche Playlist gewählt?"
Wenn das resultierende Video zerstückelt ist:
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.