docs: add re-apply, cleanup, and gen_json plans
- Re-apply: idempotent apply using track number prefix as stable anchor; album.json never touched; optional --rename-dir flag for dir renames - Cleanup: auto-remove abcde.* temp dirs after ripping + manual command - gen_json: reverse-engineer album.json from file tree using fixed naming convention; audio tags take priority over filenames for all fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6a7602387a
commit
5de6caba3a
1 changed files with 186 additions and 0 deletions
|
|
@ -335,3 +335,189 @@ class DiscMetadata:
|
||||||
|
|
||||||
Nach dem letzten `rip_disc`-Aufruf ruft `interactive_rip` einmalig
|
Nach dem letzten `rip_disc`-Aufruf ruft `interactive_rip` einmalig
|
||||||
`merge_album()` auf und schreibt album.json.
|
`merge_album()` auf und schreibt album.json.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wiederholbares Apply (Re-Apply in-place)
|
||||||
|
|
||||||
|
### Ziel
|
||||||
|
|
||||||
|
`apply` soll beliebig oft wiederholbar sein — auch nachträglich im
|
||||||
|
Jellyfin-Zielverzeichnis. Der User editiert album.json und ruft apply
|
||||||
|
erneut auf; Dateinamen, Tags und Playlist werden aktualisiert.
|
||||||
|
|
||||||
|
### Invariante: album.json bleibt immer erhalten
|
||||||
|
|
||||||
|
`apply` berührt album.json nie. Sie ist die einzige persistente
|
||||||
|
Wahrheitsquelle für alle Metadaten. Selbst wenn Tags oder Dateinamen
|
||||||
|
abweichen, definiert album.json den Sollzustand.
|
||||||
|
|
||||||
|
### Stabilität durch Tracknummer-Präfix
|
||||||
|
|
||||||
|
Der stabile Anker beim Re-Apply ist die führende Tracknummer im
|
||||||
|
Dateinamen:
|
||||||
|
|
||||||
|
```
|
||||||
|
01_-_Alter_Titel.flac → nach Edit → 01_-_Neuer_Titel.flac
|
||||||
|
```
|
||||||
|
|
||||||
|
`discover_audio_files()` identifiziert Tracks bereits nach dem
|
||||||
|
numerischen Präfix (unabhängig vom Titelanteil). Re-Apply ist damit
|
||||||
|
robust gegenüber beliebigen Titeländerungen.
|
||||||
|
|
||||||
|
### Was apply bei jedem Aufruf tut (idempotent)
|
||||||
|
|
||||||
|
1. Audiodateien per Tracknummer-Präfix identifizieren
|
||||||
|
2. Umbenennen gemäß aktuellem album.json (in-place)
|
||||||
|
3. Alle Audio-Tags neu schreiben (überschreiben)
|
||||||
|
4. Cover neu einbetten (überschreiben)
|
||||||
|
5. Playlist neu generieren (überschreiben, gleicher Dateiname)
|
||||||
|
6. album.json unangetastet lassen
|
||||||
|
|
||||||
|
### Verzeichnisumbenennung bei Albumname-Änderung
|
||||||
|
|
||||||
|
Wenn sich `album` oder `year` in album.json ändern, ändert sich der
|
||||||
|
korrekte Verzeichnisname. Im Jellyfin-Ordner ist das heikel (Jellyfin
|
||||||
|
erkennt das Album ggf. als neu).
|
||||||
|
|
||||||
|
Vorschlag: Verzeichnisumbenennung nur mit explizitem Flag:
|
||||||
|
```
|
||||||
|
musiksammlung apply --in-place --rename-dir <album_dir>
|
||||||
|
```
|
||||||
|
Ohne Flag: Dateien und Tags werden aktualisiert, Verzeichnisname bleibt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cleanup nach dem Ripping
|
||||||
|
|
||||||
|
abcde hinterlässt Arbeitsverzeichnisse unterhalb der CDn-Ordner:
|
||||||
|
|
||||||
|
```
|
||||||
|
Album/
|
||||||
|
CD1/
|
||||||
|
abcde.XXXXX/ ← Temp-Verzeichnis von abcde
|
||||||
|
track01.wav ← evtl. noch vorhandene WAV-Zwischendateien
|
||||||
|
status
|
||||||
|
mbid.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wann aufräumen
|
||||||
|
|
||||||
|
**Automatisch am Ende von Phase B** (nach erfolgreichem Ripping):
|
||||||
|
|
||||||
|
```python
|
||||||
|
for abcde_dir in cd_dir.glob("abcde.*"):
|
||||||
|
shutil.rmtree(abcde_dir)
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternativ als expliziter Befehl für manuelles Aufräumen:
|
||||||
|
```
|
||||||
|
musiksammlung cleanup <album_dir>
|
||||||
|
```
|
||||||
|
|
||||||
|
Beide Varianten sollten implementiert werden: automatisch als Default,
|
||||||
|
manuell als Fallback wenn Phase B mit Fehler abgebrochen wurde.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Neuer CLI-Befehl: gen_json
|
||||||
|
|
||||||
|
### Zweck
|
||||||
|
|
||||||
|
Rekonstruiert album.json aus dem vorhandenen Dateibaum, wenn die Datei
|
||||||
|
versehentlich gelöscht wurde. Kann auch für Alben genutzt werden, die
|
||||||
|
mit anderen Tools gerippt wurden.
|
||||||
|
|
||||||
|
```
|
||||||
|
musiksammlung gen_json <album_dir>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Namenskonvention (verbindlich festgelegt)
|
||||||
|
|
||||||
|
**Album-Verzeichnis:**
|
||||||
|
```
|
||||||
|
Sanitized_Artist_-_Sanitized_Album_Title_(YYYY)/
|
||||||
|
Sanitized_Album_Title_(YYYY)/ ← wenn Artist "Various Artists"
|
||||||
|
```
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
```
|
||||||
|
Pink_Floyd_-_The_Wall_(1979)/
|
||||||
|
Bach_-_Brandenburg_Concertos_(1967)/
|
||||||
|
Various_Artists_-_Now_Thats_What_I_Call_Music_(2001)/
|
||||||
|
```
|
||||||
|
|
||||||
|
**CDn-Unterverzeichnis** (bei Multi-Disc):
|
||||||
|
```
|
||||||
|
CD1/ CD2/ ...
|
||||||
|
```
|
||||||
|
Bei Single-Disc: Audiodateien liegen direkt im Album-Verzeichnis oder
|
||||||
|
in `CD1/` — beides wird akzeptiert.
|
||||||
|
|
||||||
|
**Track-Dateiname:**
|
||||||
|
```
|
||||||
|
NN_-_Sanitized_Track_Title.flac
|
||||||
|
NN_-_Sanitized_Track_Title_-_Sanitized_Track_Artist.flac
|
||||||
|
```
|
||||||
|
|
||||||
|
`NN` ist zweistellig mit führender Null (`01`, `02`, ..., `99`).
|
||||||
|
`_-_` (Unterstrich-Bindestrich-Unterstrich) ist der strukturelle
|
||||||
|
Trenner — kein einfacher `-` innerhalb eines Feldes ist `_-_`.
|
||||||
|
|
||||||
|
### gen_json Algorithmus
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Verzeichnisname parsen:
|
||||||
|
"Pink_Floyd_-_The_Wall_(1979)" →
|
||||||
|
artist = "Pink Floyd" (vor erstem _-_)
|
||||||
|
album = "The Wall" (zwischen _-_ und _(YYYY))
|
||||||
|
year = 1979 (aus _(YYYY))
|
||||||
|
|
||||||
|
2. CDn-Unterverzeichnisse → disc_number (Zahl aus "CD1", "CD2" etc.)
|
||||||
|
Keine CDn-Dirs → Single-Disc, disc_number = 1
|
||||||
|
|
||||||
|
3. Pro Disc: Audiodateien nach Tracknummer-Präfix sortieren:
|
||||||
|
"01_-_In_the_Flesh.flac" → track_number=1, title="In the Flesh"
|
||||||
|
"02_-_The_Thin_Ice_-_Roger_Waters.flac"
|
||||||
|
→ track_number=2, title="The Thin Ice",
|
||||||
|
artist="Roger Waters"
|
||||||
|
|
||||||
|
4. Audio-Tags lesen (mutagen) — höhere Priorität als Dateiname:
|
||||||
|
- title, artist: aus Tags übernehmen wenn vorhanden
|
||||||
|
(Tags enthalten Original-Strings ohne Sanitizing)
|
||||||
|
- duration_ms: aus Audiodatei (exakt, besser als MB oder TOC)
|
||||||
|
- genre: nur aus Tags verfügbar, nirgends im Dateinamen kodiert
|
||||||
|
|
||||||
|
5. album.json schreiben (fehlende Felder als null)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Daten-Rangfolge in gen_json
|
||||||
|
|
||||||
|
| Feld | Quelle 1 (bevorzugt) | Quelle 2 (Fallback) |
|
||||||
|
|------|---------------------|---------------------|
|
||||||
|
| title | Audio-Tag | Dateiname (desanitized) |
|
||||||
|
| artist | Audio-Tag | Dateiname / Verzeichnis |
|
||||||
|
| album | Audio-Tag | Verzeichnisname |
|
||||||
|
| year | Audio-Tag | Verzeichnisname _(YYYY) |
|
||||||
|
| genre | Audio-Tag | — (bleibt null) |
|
||||||
|
| duration_ms | Audiodatei (mutagen) | — |
|
||||||
|
| disc_number | CDn-Verzeichnis | — |
|
||||||
|
| track_number | Dateiname-Präfix | Audio-Tag |
|
||||||
|
|
||||||
|
### Was gen_json nicht rekonstruieren kann
|
||||||
|
|
||||||
|
- `disc.disc_id` (physischer TOC-Fingerprint — nicht in Dateien)
|
||||||
|
- `disc.name` (z.B. "Live in Berlin" — nicht im Dateinamen kodiert)
|
||||||
|
- `genre` wenn Audio-Tags fehlen
|
||||||
|
|
||||||
|
### Klassik: Komponist vs. Interpret
|
||||||
|
|
||||||
|
Beide Felder werden in den Audio-Tags gespeichert (COMPOSER-Tag bei
|
||||||
|
FLAC/MP3). `gen_json` liest COMPOSER aus den Tags und kann Komponist
|
||||||
|
von Interpret trennen — ohne spezielle Namenskonvention im Dateinamen.
|
||||||
|
|
||||||
|
Der Dateinamen-Titel enthält bei Klassik typischerweise Werk + Satz:
|
||||||
|
```
|
||||||
|
01_-_Symphony_No_5_Op_67_I_Allegro_con_brio.flac
|
||||||
|
```
|
||||||
|
Komponist steht im Verzeichnisnamen (`Bach_-_...`) und im COMPOSER-Tag.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue