docs: add parallel metadata/ripping workflow plan (Phase A/B/C)
Describes the restructured workflow where metadata gathering (TOC, CDDB, MB, Vision-LLM) happens before ripping starts, so the user can review and edit album.json before committing to the long rip — not after. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c791812755
commit
6a7602387a
1 changed files with 131 additions and 0 deletions
|
|
@ -204,3 +204,134 @@ Testvorgaben:
|
||||||
- Track-Matching bei unterschiedlicher Track-Anzahl
|
- Track-Matching bei unterschiedlicher Track-Anzahl
|
||||||
- disc_id korrekt pro Disc zugeordnet
|
- disc_id korrekt pro Disc zugeordnet
|
||||||
- Fehlende Quellen (None) robust behandelt
|
- Fehlende Quellen (None) robust behandelt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Parallelisierung: Informationsbeschaffung vor dem Rippen
|
||||||
|
|
||||||
|
### Kernidee
|
||||||
|
|
||||||
|
Die CD muss für zwei Operationen physisch im Laufwerk liegen, aber diese
|
||||||
|
brauchen sich nicht zu überlappen:
|
||||||
|
|
||||||
|
```
|
||||||
|
Operation A: TOC lesen (cd-discid) ~2 Sekunden
|
||||||
|
Operation B: Audio rippen (cdparanoia) 20–60 Minuten pro Disc
|
||||||
|
```
|
||||||
|
|
||||||
|
Heute sind beide in einem monolithischen Durchlauf verschmolzen. Das
|
||||||
|
Umordnen kostet nichts — die CD darf ruhig zweimal im Laufwerk liegen.
|
||||||
|
|
||||||
|
### Neuer Ablauf (Drei Phasen A / B / C)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Phase A: Informationsbeschaffung (~30s – 5 min) │
|
||||||
|
│ │
|
||||||
|
│ 1. CD einlegen (einmalig oder pro Disc bei Multi-Disc) │
|
||||||
|
│ 2. cd-discid → TOC: disc_id, Offsets, Laufzeiten │
|
||||||
|
│ 3. CDDB-Lookup → artist, album, year, genre, tracks │
|
||||||
|
│ 4. EAN-Scan → MusicBrainz → Album + MBID │
|
||||||
|
│ 5. CAA-Download → front.jpg, back.jpg │
|
||||||
|
│ 6. back.jpg → Vision-LLM (läuft parallel, ~1–3 min) │
|
||||||
|
│ 7. merge_album() → album.json (preliminary) │
|
||||||
|
│ 8. "album.json bereit — bitte prüfen." │
|
||||||
|
│ 9. User editiert album.json (optional, zweites │
|
||||||
|
│ Terminal oder nach Prompt) │
|
||||||
|
│ 10. "Rippen starten? [Enter]" │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Phase B: Audio-Ripping (~20–60 min pro Disc) │
|
||||||
|
│ │
|
||||||
|
│ abcde läuft im Vordergrund (Terminal zeigt Progress) │
|
||||||
|
│ Während des Rippens im zweiten Terminal: │
|
||||||
|
│ - album.json editieren (jederzeit möglich) │
|
||||||
|
│ - Vision-LLM-Ergebnis (falls noch ausstehend) │
|
||||||
|
│ wird nach Abschluss nachgemergt │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Phase C: Apply (~30s) │
|
||||||
|
│ │
|
||||||
|
│ Liest finales album.json (evtl. editiert während B) │
|
||||||
|
│ organize → tag → embed → playlist │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Was der Hauptgewinn ist
|
||||||
|
|
||||||
|
```
|
||||||
|
Heute: Metadaten ── Rippen (60 min) ── album.json sehen ── editieren
|
||||||
|
Neu: Metadaten ── album.json sehen ── [editieren] ── Rippen (60 min)
|
||||||
|
└── Vision-LLM läuft parallel zum Rippen
|
||||||
|
```
|
||||||
|
|
||||||
|
Der User sieht die Metadaten **vor** dem langen Warten. Editing erfolgt
|
||||||
|
mit vollständiger Information, nicht blind im Nachhinein.
|
||||||
|
|
||||||
|
### Warum kein Hintergrund-Ripping
|
||||||
|
|
||||||
|
Hintergrund-Ripping (subprocess mit PID-Datei) ist technisch machbar,
|
||||||
|
erhöht aber die Komplexität (PID-Management, Fehlerbehandlung, Status-
|
||||||
|
Tracking) ohne entscheidenden Mehrwert: Der User kann während des
|
||||||
|
Vordergrund-Rippings jederzeit ein zweites Terminal öffnen und album.json
|
||||||
|
dort editieren. `$EDITOR album.json` reicht.
|
||||||
|
|
||||||
|
### Abcde: keine Änderung nötig
|
||||||
|
|
||||||
|
abcde hat Aktions-Flags (`-a cddb,read,encode,tag`), die eine Trennung
|
||||||
|
erlauben würden. Da wir CDDB und TOC aber bereits **vor** abcde über
|
||||||
|
eigene Module abfragen (`lookup_by_discid`, `cd-discid`), kann abcde
|
||||||
|
unverändert für Phase B genutzt werden — nur mit dem Wissen, dass seine
|
||||||
|
CDDB-Ausgabe bereits in album.json konsolidiert ist.
|
||||||
|
|
||||||
|
### Multi-Disc-Verhalten
|
||||||
|
|
||||||
|
```
|
||||||
|
Disc 1: Phase A (~2 min) → "Rippen starten?" → Phase B Disc 1 (~45 min)
|
||||||
|
Disc 2: Phase A (~2 min) → "Rippen starten?" → Phase B Disc 2 (~45 min)
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Jede Disc wird sequenziell behandelt (ein Laufwerk). Phase A aller Discs
|
||||||
|
könnte theoretisch vorab gebündelt werden (alle Discs kurz einlegen, TOC
|
||||||
|
lesen), ist aber als optionale Optimierung einzustufen.
|
||||||
|
|
||||||
|
### Änderungsbedarf in ripper.py
|
||||||
|
|
||||||
|
Die heutige `interactive_rip`-Funktion wird aufgeteilt in:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def gather_metadata(disc_num, config, scanner) -> DiscMetadata:
|
||||||
|
"""Phase A: TOC, CDDB, MB, Vision-LLM — kein Rippen."""
|
||||||
|
...
|
||||||
|
|
||||||
|
def rip_disc(disc_num, config) -> Path:
|
||||||
|
"""Phase B: abcde — kein Netzwerk, kein LLM."""
|
||||||
|
...
|
||||||
|
|
||||||
|
def interactive_rip(config):
|
||||||
|
"""Orchestriert: für jede Disc gather_metadata → confirm → rip_disc."""
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
`DiscMetadata` ist ein internes Dataclass/NamedTuple das alle Rohdaten
|
||||||
|
einer Disc bis zum Merge trägt:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class DiscMetadata:
|
||||||
|
disc_number: int
|
||||||
|
discid_line: str # Rohstring aus cd-discid
|
||||||
|
cddb_result: CddbResult | None
|
||||||
|
mb_album: Album | None # nur bei erster Disc sinnvoll
|
||||||
|
mb_mbid: str | None
|
||||||
|
vision_album: Album | None # Ergebnis des Background-Threads
|
||||||
|
uploaded_photo: Path | None
|
||||||
|
```
|
||||||
|
|
||||||
|
Nach dem letzten `rip_disc`-Aufruf ruft `interactive_rip` einmalig
|
||||||
|
`merge_album()` auf und schreibt album.json.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue