Musiksammlung/docs/Grundsaetzliche_Audio_Koventionen_und_Methoden_Jellyfin.md
dschlueter 41378e8a10 Add test utilities and Jellyfin audio conventions doc
- test_ean_scan.py: interactive EAN barcode scanning test via scanner server
- test_backcover_scan.py: comprehensive backcover metadata extraction test
- docs/Grundsaetzliche_Audio_Koventionen_und_Methoden_Jellyfin.md: notes on
  audio conventions and naming methods for Jellyfin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 11:59:02 +01:00

33 KiB
Raw Blame History

Ich digitalisiere gerade meine große CD Sammlung. Wie kann ich die Metadaten mit den Musikdateien verbinden?

Du verbindest die Infos (Titel, Album, Artist, Jahr, Cover …) direkt als Tags in den Dateien je nach Format z.B. ID3 (MP3) oder Vorbis-Kommentare (FLAC/OGG).12

Grundprinzip

  • Jede Audiodatei enthält ein Tag-Set: Titel, Album, Artist, Tracknummer, Discnummer, Jahr, Genre, Album-Artist, Cover-Art etc.21
  • Jellyfin und andere Player lesen primär diese Tags; die Ordnerstruktur hilft vor allem bei der AlbumGruppe und MehrfachCDs.34

Wenn du ein GUITool willst

  • Mp3tag (läuft auch gut unter Wine) zum massenhaften Bearbeiten von MP3, FLAC, OGG, MP4 usw.56
  • Workflow:
    • AlbumOrdner laden.
    • Basisdaten (Album, Artist, Jahr, Genre, AlbumArtist) im linken Panel setzen.
    • Titel pro Track eintragen (oder aus deiner eigenen Datenquelle reinkopieren).
    • Cover als Bilddatei ins CoverFeld ziehen → wird eingebettet.5

Wenn du es skripten willst (Python)

  • Nutze die Bibliothek mutagen, die MP3, FLAC, OGG, AAC usw. unterstützt und Tags verlustfrei schreibt.78910
  • Beispiel für FLAC (pseudocodehaft, an deine Struktur anpassbar):
from mutagen.flac import FLAC
from mutagen.id3 import ID3, APIC
from pathlib import Path

album_dir = Path("/pfad/zum/album")
cover_data = Path(album_dir / "cover.jpg").read_bytes()

tracks = [
    "Titel 1",
    "Titel 2",
    # ...
]

for i, audio_file in enumerate(sorted(album_dir.glob("*.flac")), start=1):
    audio = FLAC(audio_file)
    audio["title"] = tracks[i-1]
    audio["album"] = "Albumname"
    audio["artist"] = "Künstler"
    audio["albumartist"] = "Künstler"
    audio["tracknumber"] = str(i)
    audio["date"] = "1987"
    audio["genre"] = "Rock"
    # Cover einmal pro Datei einbetten
    audio.add_picture({
        "data": cover_data,
        "mime": "image/jpeg",
        "type": 3,  # Front-Cover
        "desc": "Cover"
    })
    audio.save()
  • Für MP3 verwendest du in mutagen die Klasse mutagen.mp3.MP3 mit ID3Frames (TIT2, TALB, TPE1, TPE2, APIC etc.).97

Jellyfinrelevante Felder

  • Wichtige Tags pro Track:
    • Titel (Title)
    • Artist (TrackArtist)
    • Album
    • AlbumArtist (für Sampler z.B. „Various Artists“)
    • Tracknummer, Discnummer (+ Gesamtzahl Discs)
    • Jahr / Erscheinungsdatum
    • Genre
  • Wichtige Dateien im AlbumOrdner:
    • Eingebettetes Cover im Tag, zusätzlich oft folder.jpg/cover.jpg im Ordner.113

Ordnerstruktur + Tags

Eine typische, für Jellyfin gut passende Struktur:

  • Artist/Album (Jahr)/CD1/01 Titel.flac mit passenden Tags (Album, Discnumber=1, Tracknumber=1, …).
  • Jellyfin kommt auch mit „viel in einem Ordner“ klar, solange die Tags sauber sind, aber mit AlbumOrdnern behältst du als Mensch den Überblick besser.43

Wenn du mir sagst, ob du aktuell FLAC, MP3 oder beides benutzt und ob du lieber bei GUI oder Python bleiben willst, kann ich dir ein konkretes TaggingSkript oder Mp3tagPreset passend zu deinem RippingWorkflow bauen. 12131415


Welche Angaben un Meta-Daten sind sinnvoll, wenn ich Audio-CDs oder Audio-CD-Alben in Jellyfin verwalten und präsentien will. Welche Infos benötige ich, welche Infos sind nice to have und in welcher Dateistruktur speichere ich die Daten (meine digitalisierte CD-Sammlung) am besten im Jellyfin Audio-Verzeichnis?

Für Jellyfin zählen vor allem sauber gesetzte Tags in den Dateien und eine halbwegs konsistente Ordnerstruktur pro Album.1617

Pflicht-Metadaten (für Jellyfin sinnvoll / „brauche ich“)

Pro Track solltest du mindestens setzen:1716

  • Titel (Title)
  • Artist (Interpret dieses Tracks)
  • Album
  • Album-Artist (für normale Alben = Artist, für Sampler z.B. „Various Artists“)181617
  • Tracknummer
  • Discnummer und Gesamtzahl Discs (Disc number, Total discs) wichtig für MehrfachCDAlben.1916
  • Jahr oder Erscheinungsdatum (Date/Year) für die zeitliche Sortierung.2017
  • Eingebettetes Front-Cover (plus idealerweise folder.jpg im Albumordner) für die Kachelansicht.1617

Ohne diese Felder wirkt die JellyfinAnsicht schnell chaotisch (Alben nicht korrekt gruppiert, falsche Sortierung, keine Cover).211916

Sinnvolle Zusatzinfos („nice to have“)

  • Genre ermöglicht GenreFilter und Smart Playlists.2217
  • Komponist (Composer) wichtig bei Klassik, Soundtracks.2218
  • Album-Sort, Artist-Sort (sortierbare Varianten, z.B. „Beatles, The“) für saubere AZListen.18
  • Originales Erscheinungsjahr getrennt von Re-ReleaseJahr (falls du beides pflegst).20
  • Kommentar / Tagging-Notizen (z.B. Quelle, Remaster, eigene Kennzeichnung).22
  • Mehrere Album-Artists bei Kollaborationen (durch Trenner wie „Artist1; Artist2“ im AlbumArtistFeld).2318

Jellyfin nutzt diese Felder nicht immer explizit für das UI, aber sie helfen dir bei Filtern, Suchen und konsistenter Darstellung.231618

Ordner- und Dateistruktur (empfohlen)

Jellyfin: „Ein Album = ein Ordner“, der Rest erfolgt über Tags.1716

Top-Level

  • /media/music als JellyfinBibliothek vom Typ „Musik“.17

Album-Struktur

Empfohlenes Schema:1617

  • /media/music/Artist/Album (Jahr)/Trackdateien

Beispiel:17

  • /media/music/Daft Punk/Random Access Memories (2013)/01 - Give Life Back to Music.flac

Wichtiges aus der JellyfinDoku:16

  • Ein Ordner enthält genau ein Album (bei MehrfachCDs alle Discs dieses Albums).
  • Jellyfin verlässt sich primär auf die eingebetteten Tags; Dateinamen sind zweitrangig und werden nur genutzt, wenn Tags fehlen.241617

Mehrfach-CD-Alben

Zwei praktikable Varianten, beide funktionieren, solange die Tags stimmen:1617

  1. Alles in einem Ordner (empfohlen von Jellyfin):
    • /media/music/Artist/Album (Jahr)/101 - Track.flac
    • /media/music/Artist/Album (Jahr)/201 - Track.flac oder
    • /media/music/Artist/Album (Jahr)/CD1 - 01 - Track.flac
    • Tags: discnumber=1/2, discnumber=2/2 usw.1916
  2. Unterordner pro Disc (auch ok):
    • /media/music/Artist/Album (Jahr)/CD1/01 - Track.flac
    • /media/music/Artist/Album (Jahr)/CD2/01 - Track.flac
    • Jellyfin nutzt trotzdem die DiscTags zur Gruppierung der Discs, nicht den Ordnernamen.16

Was darf „chaotisch“ sein?

  • Du kannst theoretisch alle Tracks in einem großen Ordner halten; Jellyfin kann über Tags trotzdem Alben und Artists bauen.2524
  • Praktisch hilft dir selbst eine strukturierte Form Artist/Album enorm, z.B. bei Backups, manueller Nacharbeit und Tagging mit externen Tools.2417

Kurze Empfehlung für dein Projekt

  1. Ripping: immer gleich mit Tags füllen (Titel, Album, Artist, AlbumArtist, Track/Discnummer, Jahr, Genre).2216
  2. Albumordner: Artist/Album (Jahr)/, bei MultiCD optional CD1/, CD2/ darunter.1716
  3. In jeden Albumordner: eingebettetes Cover in allen Dateien + folder.jpg (Front), optional back.jpg.1716

Wenn du mir ein konkretes BeispielAlbum gibst (z.B. 3CDSammlung, Sampler, Klassik), skizziere ich dir genau, welche Tags du setzen solltest (inkl. BeispielWerten) und wie die Ordner dafür aussehen könnten. 2627282930


1. Wie sehen typische Verzeichnis-Bäume für Klassik, Pop, Volksmusik und Sonstige bei Jellyfin aus ? 2. Was muss und kann ich in die Tags der Audio-Dateien schreiben ?

Für Jellyfin kannst du für alle Musikrichtungen denselben Grundaufbau nutzen; Unterschiede liegen vor allem in den Tags (z.B. Komponist bei Klassik).3132

1. Typische Verzeichnisbäume

JellyfinVorgabe: Ein Ordner enthält genau ein Album (bzw. eine SingleVeröffentlichung).3331

Pop / Rock / Volksmusik / „Sonstige“

Übliche Struktur:

/music
└── Pop
    ├── Abba
    │   ├── 1976 - Arrival
    │   │   ├── 01 - When I Kissed the Teacher.flac
    │   │   ├── 02 - Dancing Queen.flac
    │   │   └── folder.jpg
    │   └── 1979 - Voulez-Vous
    └── Queen
        └── 1975 - A Night at the Opera

Oder ohne GenreEbene:

/music
└── Abba
    └── Arrival (1976)
        ├── 01 - When I Kissed the Teacher.flac
        └── folder.jpg

Beides funktioniert, da Jellyfin Alben primär über „ein Ordner = ein Album“ und Tags erkennt.343531

Klassik

Hier lohnt sich eine Ebene für Komponisten bzw. Sammler:3236

Variante A nach Komponist:

/music-classical
└── Beethoven, Ludwig van
    ├── Symphonies - Karajan (DG, 1963)
    │   ├── CD1
    │   │   ├── 01 - Symphony No.1 - I.flac
    │   │   └── 02 - Symphony No.1 - II.flac
    │   └── folder.jpg
    └── Piano Sonatas - Kempff

Variante B nach Interpret/Ensemble:

/music-classical
└── Berliner Philharmoniker
    └── Beethoven - Symphonies (Karajan, 1963)
        ├── CD1
        └── folder.jpg

Beide Varianten sind ok; Jellyfin gruppiert letztlich nach Tags (Composer, Album, AlbumArtist).3132

Singles / EPs / Sampler

  • Singles als „MiniAlbum“ im eigenen Ordner ablegen, damit Jellyfin sie nicht zu Alben zusammenwirft.33
  • Sampler/Compilations z.B.:
/music
└── Compilations
    └── Bravo Hits 01 (1992)
        ├── 01 - Track.flac
        └── folder.jpg

Wichtig: AlbumArtist = „Various Artists“, Artist = je Track.3732


2. PflichtTags für Jellyfin

Diese Felder solltest du konsequent pro Track setzen, egal ob Klassik, Pop oder Volksmusik:3831

  • Title Tracktitel.
  • Album Albumname exakt gleich für alle Tracks des Albums.31
  • Artist Interpret des Tracks (bei Klassik meist Solist/Ensemble/Dirigent, nicht der Komponist).3632
  • AlbumArtist „HauptArtist“ des Albums (Band/Interpret, bei Samplern „Various Artists“; bei Kollabos mehrere Artists mit ; oder /).3731
  • Track number reine Nummer (1, 2, 3 …).
  • Disc number und Total discs wichtig für MehrfachCDAlben.3931
  • Date/Year Erscheinungsjahr bzw. ReleaseDatum.3631
  • Eingebettetes Cover (Front) in jeder Datei; zusätzlich folder.jpg im Albumordner.4031

Ohne diese Tags gibt es z.B. falsch gruppierte Alben, fehlende Cover oder durcheinander sortierte Tracks.413931


3. Sinnvolle ZusatzTags nach Genre

Für Pop / Rock / Volksmusik

  • Genre möglichst konsistent (z.B. „Pop“, „Rock“, „Volksmusik“, nicht 20 Varianten).4243
  • Artist sort / AlbumArtist sort für „The Beatles“ → „Beatles, The“.32
  • Comment Herkunft (CD, VinylRip, Remaster), eigene Kennzeichnung.
  • Composer für SingerSongwriter oder wichtige Songwriter.36
  • Lyrics optional (LRC/embedded), Jellyfin kann Texte darstellen über Plugins.3836

Speziell für Klassik

Jellyfin hat (über MusicBrainzMapping) Felder, die für Klassik nützlich sind:3236

  • Composer Komponist (z.B. „Beethoven, Ludwig van“).
  • Conductor Dirigent.
  • Ensemble/Orchestra Orchester/Chor.
  • Performer Solisten (Violin, Piano etc.).
  • Work Werk (z.B. „Symphony No.5 in C minor, Op.67“).
  • Movement Satz (z.B. „I. Allegro con brio“).

Viele Tagger (Picard, puddletag, Mp3tag) können diese Felder schreiben; Jellyfin zeigt sie in den Detailansichten und in „People“ an.3236

Sampler / Compilations

  • AlbumArtist = „Various Artists“ (wichtig für Listen in Jellyfin).4437
  • Artist = jeweiliger Interpretenname pro Track.
  • Genre „Compilation“ oder das eigentliche Genre (z.B. „Pop“), je nach deiner Sortierlogik.4332

4. Optionale Metadaten / PowerUser-Felder

  • Mehrere Genres getrennt durch ;, / oder \ (abhängig vom Tool); Plugins können das splitten.43
  • Mood / Style / Tags (z.B. „melancholic“, „live“, „90s“), um später Sammlungen/Smart Playlists zu bauen.4243
  • Producer, Writer, Lyricist wird in „People“ angezeigt, wenn gesetzt.36
  • ReplayGainTags (track/album gain) für konsistente Lautstärke; von JellyfinClients teils unterstützt.38
  • Lokale .nfoDateien pro Album/Artist, wenn du sehr spezifische Beschreibungen/Bilder pflegen willst.45

5. Kurzempfohlene Bäume je Kategorie

Nur als Illustration passe es an deine Realität an:

/media
├── music-pop
│   └── Artist/Year - Album/Tracks...
├── music-classical
│   └── Composer/Work - Conductor (Label, Year)/CDx/Tracks...
├── music-folk
│   └── Region or Artist/Year - Album/Tracks...
└── music-misc
    └── Thema oder Artist/Album/Tracks...

Die eigentliche „Intelligenz“ liegt in den Tags; die Bäume dienen dir vor allem zur menschlichen Orientierung und für getrennte JellyfinBibliotheken (z.B. Pop, Klassik, Hörbücher).464431

Wenn du magst, können wir im nächsten Schritt ein konkretes TagSchema für „BeispielKlassikAlbum (3 CDs)“ vs. „PopAlbum (1 CD)“ durchdeklinieren, inkl. Beispielwerten für alle relevanten Felder. 4748


ja

Dann machen wir zwei konkrete Beispiele: ein 3CDKlassikAlbum und ein 1CDPopAlbum, jeweils mit Baum + Tags.

Beispiel 1: KlassikAlbum, 3 CDs

Verzeichnisbaum

/music-classical
└── Beethoven, Ludwig van
    └── Symphonies - Karajan (DG, 1963)
        ├── CD1
        │   ├── 01 - Symphony No.1 - I.flac
        │   ├── 02 - Symphony No.1 - II.flac
        │   └── ...
        ├── CD2
        │   ├── 01 - Symphony No.3 - I.flac
        │   └── ...
        ├── CD3
        │   ├── 01 - Symphony No.5 - I.flac
        │   └── ...
        └── folder.jpg

Tags pro Track (Muss)

Für alle Tracks des Albums:

  • Album: Beethoven: Symphonies (Karajan, 1963)
  • AlbumArtist: Herbert von Karajan; Berliner Philharmoniker (oder nur Herbert von Karajan, je nach Systematik)
  • Date/Year: 1963
  • Genre: Classical

Pro Track:

  • Title: Symphony No.5 in C minor, Op.67: I. Allegro con brio
  • Artist: Berliner Philharmoniker; Herbert von Karajan
  • Track number: 1, 2, 3 … (je CD neu beginnend)
  • Disc number: 1, 2 oder 3
  • Total discs: 3
  • Embedded Cover: front cover als Bild im Tag

Tags pro Track (empfohlen für Klassik)

  • Composer: Beethoven, Ludwig van
  • Conductor: Herbert von Karajan
  • Ensemble/Orchestra: Berliner Philharmoniker
  • Work: Symphony No.5 in C minor, Op.67
  • Movement: I. Allegro con brio
  • Artist sort: Karajan, Herbert von; Berliner Philharmoniker
  • Composer sort: Beethoven, Ludwig van

Damit kann Jellyfin sauber nach Komponist, Dirigent, Album und ggf. Werk sortieren.495051


Beispiel 2: PopAlbum, 1 CD

Verzeichnisbaum

/music-pop
└── Queen
    └── A Night at the Opera (1975)
        ├── 01 - Death on Two Legs.flac
        ├── 02 - Lazing on a Sunday Afternoon.flac
        ├── ...
        └── folder.jpg

Tags pro Track (Muss)

Für alle Tracks des Albums:

  • Album: A Night at the Opera
  • AlbumArtist: Queen
  • Date/Year: 1975
  • Genre: Rock

Pro Track:

  • Title: Bohemian Rhapsody
  • Artist: Queen
  • Track number: 11 (oder entsprechend)
  • Disc number: 1
  • Total discs: 1
  • Embedded Cover: front cover

Tags pro Track (empfohlen)

  • Artist sort: Queen (oder bei „The Beatles“ z.B. Beatles, The)
  • Composer: Freddie Mercury (optional)
  • Comment: CD rip 2026-02, remaster 2011 o.ä.
  • Mehrere Genres: z.B. Rock; Classic Rock (je nach TaggerTrenner)

Damit erscheinen in Jellyfin ArtistAnsicht, AlbumAnsicht und Sortierung so, wie man es von „normaler“ PopSammlung erwartet.505249


Kurz: Was du dir als „Schema“ merken kannst

  • Klassik:
    • Ordner: nach Komponist oder Ensemble, pro Aufnahme ein Albumordner, CDUnterordner optional.
    • Tags: Composer, Conductor, Ensemble, Work, Movement + Standardfelder (Album, AlbumArtist, Track/Disc, Year, Genre).
  • Pop/Volksmusik/Sonstige:
    • Ordner: /Genre/Artist/Year - Album/Trackdateien.
    • Tags: Album, AlbumArtist, Artist, Track/Disc, Year, Genre, optional Composer, Artist sort.

Wenn du willst, können wir als nächstes ein JSONSchema/Mapping definieren (z.B. wie dein Programm die Infos intern speichert und dann in Tags + Ordnernamen ausspielt).


ja

Dann skizziere ich dir ein schlankes JSONSchema, das du als interne „Album-Definition“ nutzen kannst; daraus kannst du Ordnernamen + Tags generieren.5354

JSONSchema für ein Album

{
  "album_id": "beethoven-karajan-dg-1963",
  "category": "classical",              
  "library": "music-classical",         

  "album": {
    "title": "Beethoven: Symphonies (Karajan, 1963)",
    "sort_title": "Beethoven: Symphonies (Karajan, 1963)",
    "year": 1963,
    "original_year": 1963,
    "label": "Deutsche Grammophon",
    "genres": ["Classical"],
    "album_artist": "Herbert von Karajan; Berliner Philharmoniker",
    "album_artist_sort": "Karajan, Herbert von; Berliner Philharmoniker"
  },

  "classical": {
    "composer": "Beethoven, Ludwig van",
    "composer_sort": "Beethoven, Ludwig van",
    "conductor": "Herbert von Karajan",
    "ensemble": "Berliner Philharmoniker"
  },

  "discs": [
    {
      "disc_number": 1,
      "disc_title": "Symphonies Nos. 1 & 2",
      "tracks": [
        {
          "track_number": 1,
          "title": "Symphony No.1 in C major, Op.21: I. Adagio molto  Allegro con brio",
          "work": "Symphony No.1 in C major, Op.21",
          "movement": "I. Adagio molto  Allegro con brio",
          "artists": ["Berliner Philharmoniker", "Herbert von Karajan"],
          "soloists": [],
          "comment": ""
        }
      ]
    }
  ],

  "artwork": {
    "front": "cover_front.jpg",
    "back": "cover_back.jpg",
    "booklet": ["booklet_01.jpg", "booklet_02.jpg"]
  }
}

PopAlbum wäre dasselbe Schema, nur ohne classicalBlock und ohne work/movement, dafür ggf. lyrics, writer etc.54

Mapping: JSON → Ordnername

Aus obigem Objekt generierst du z.B.:

/media/<library>/
  Composer oder Artist /
    "<year> - <album.title>"/
      "CD<disc_number>"/"TT - Title.ext"

KlassikBeispiel:

/media/music-classical/Beethoven, Ludwig van/
  1963 - Beethoven: Symphonies (Karajan, 1963)/
    CD1/01 - Symphony No.1 in C major, Op.21- I. Adagio molto  Allegro con brio.flac

PopBeispiel:

"category": "pop",
"library": "music-pop",
"album": { "title": "A Night at the Opera", "year": 1975, "album_artist": "Queen" }

/media/music-pop/Queen/1975 - A Night at the Opera/01 - Death on Two Legs.flac

Mapping: JSON → TagFelder

Pro Track kannst du in deinem Tagger (mutagen oder ähnlich) so mappen:5554

Pflichtfelder:

  • TITLEtrack.title
  • ALBUMalbum.title
  • ALBUMARTISTalbum.album_artist
  • ARTISTjoin(track.artists)
  • TRACKNUMBERtrack.track_number
  • DISCNUMBERdisc.disc_number
  • DISCTOTALlen(discs)
  • DATE / YEARalbum.year
  • GENREjoin(album.genres)

KlassikZusatz:

  • COMPOSERclassical.composer
  • CONDUCTORclassical.conductor
  • ENSEMBLE/ORCHESTRAclassical.ensemble
  • WORKtrack.work
  • MOVEMENTtrack.movement

Sonstige:

  • COMMENTtrack.comment oder globaler Kommentar
  • ALBUMSORTalbum.sort_title
  • ALBUMARTISTSORTalbum.album_artist_sort

Cover:

  • FrontCover aus artwork.front als EmbeddedBild + als folder.jpg im Albumordner.5653

Wenn du möchtest, formuliere ich dir im nächsten Schritt ein kleines PythonPseudomodul, das genau dieses JSON einliest und daraus Ordner + FLACTags erzeugt (inkl. Hook für dein RippingErgebnis).


ja

Hier ist ein kompaktes PythonGrundgerüst, das dein JSON einliest, Verzeichnisse anlegt und FLACTags mit Mutagen setzt.57585960

Annahmen

  • Du hast pro Album eine JSONDatei wie im letzten Beispiel.
  • Die gerippten FLACs liegen schon in einem „Roh“-Ordner (z.B. input_disc1/track01.flac usw.).
  • Dein Skript baut Zielordner + Dateinamen und schreibt alle Tags.

Beispielmodul album_builder.py

from pathlib import Path
import json
from mutagen.flac import FLAC

BASE_DIR = Path("/media")  # Root für deine Libraries

def load_album(json_path: Path) -> dict:
    with json_path.open("r", encoding="utf-8") as f:
        return json.load(f)

def build_album_path(album_meta: dict) -> Path:
    lib = album_meta["library"]          # z.B. "music-classical"
    cat = album_meta["category"]         # "classical" / "pop" ...
    album = album_meta["album"]
    classical = album_meta.get("classical", {})

    if cat == "classical":
        composer = classical.get("composer_sort") or classical.get("composer") or "Unknown"
        base = BASE_DIR / lib / composer
    else:
        artist = album.get("album_artist_sort") or album.get("album_artist") or "Unknown"
        base = BASE_DIR / lib / artist

    year = album.get("year")
    title = album["title"]
    folder_name = f"{year} - {title}" if year else title
    return base / folder_name

def build_track_filename(disc_number: int, track_number: int, title: str, ext="flac") -> str:
    tn = f"{track_number:02d}"
    return f"{tn} - {title}.{ext}"

def tag_flac_file(
    file_path: Path,
    album_meta: dict,
    disc_meta: dict,
    track_meta: dict,
    total_discs: int,
    cover_data: bytes | None = None,
):
    album = album_meta["album"]
    classical = album_meta.get("classical", {})

    audio = FLAC(file_path)

    # Grundtags
    audio["TITLE"] = track_meta["title"]
    audio["ALBUM"] = album["title"]
    audio["ALBUMARTIST"] = album["album_artist"]
    audio["ARTIST"] = "; ".join(track_meta.get("artists") or [album["album_artist"]])
    audio["TRACKNUMBER"] = str(track_meta["track_number"])
    audio["DISCNUMBER"] = str(disc_meta["disc_number"])
    audio["DISCTOTAL"] = str(total_discs)

    if "year" in album:
        audio["DATE"] = str(album["year"])
    if album.get("genres"):
        audio["GENRE"] = "; ".join(album["genres"])

    # KlassikTags
    if album_meta.get("category") == "classical":
        if "composer" in classical:
            audio["COMPOSER"] = classical["composer"]
        if "conductor" in classical:
            audio["CONDUCTOR"] = classical["conductor"]
        if "ensemble" in classical:
            audio["ENSEMBLE"] = classical["ensemble"]
        if track_meta.get("work"):
            audio["WORK"] = track_meta["work"]
        if track_meta.get("movement"):
            audio["MOVEMENT"] = track_meta["movement"]

    # Sortierfelder
    if album.get("sort_title"):
        audio["ALBUMSORT"] = album["sort_title"]
    if album.get("album_artist_sort"):
        audio["ALBUMARTISTSORT"] = album["album_artist_sort"]

    # Kommentar
    if track_meta.get("comment"):
        audio["COMMENT"] = track_meta["comment"]

    # Cover einbetten (einheitliches FrontCover pro Album)
    if cover_data is not None:
        from mutagen.flac import Picture
        pic = Picture()
        pic.data = cover_data
        pic.type = 3  # Front Cover
        pic.mime = "image/jpeg"
        pic.desc = "Cover"
        audio.clear_pictures()
        audio.add_picture(pic)

    audio.save()

def process_album(json_path: Path, input_root: Path):
    album_meta = load_album(json_path)
    target_album_dir = build_album_path(album_meta)
    target_album_dir.mkdir(parents=True, exist_ok=True)

    # Cover in Ordner kopieren + Bytes laden
    artwork = album_meta.get("artwork", {})
    front_name = artwork.get("front")
    cover_bytes = None
    if front_name:
        cover_src = json_path.parent / front_name
        if cover_src.is_file():
            cover_bytes = cover_src.read_bytes()
            cover_dst = target_album_dir / "folder.jpg"
            if cover_src.suffix.lower() != ".jpg":
                cover_dst.write_bytes(cover_bytes)
            else:
                if cover_src.resolve() != cover_dst.resolve():
                    cover_dst.write_bytes(cover_bytes)

    discs = album_meta["discs"]
    total_discs = len(discs)

    for disc in discs:
        disc_no = disc["disc_number"]
        disc_title = disc.get("disc_title")

        # CDUnterordner optional:
        if total_discs > 1:
            disc_dir = target_album_dir / f"CD{disc_no}"
            disc_dir.mkdir(parents=True, exist_ok=True)
        else:
            disc_dir = target_album_dir

        # Hier musst du definieren, wo die RohFiles liegen:
        # z.B. input_root/<album_id>/disc<nr>/trackXX.flac
        raw_disc_dir = input_root / album_meta["album_id"] / f"disc{disc_no}"

        for track in disc["tracks"]:
            src_file = raw_disc_dir / f"track{track['track_number']:02d}.flac"
            filename = build_track_filename(disc_no, track["track_number"], track["title"])
            dst_file = disc_dir / filename

            dst_file.parent.mkdir(parents=True, exist_ok=True)
            dst_file.write_bytes(src_file.read_bytes())

            tag_flac_file(
                dst_file,
                album_meta=album_meta,
                disc_meta=disc,
                track_meta=track,
                total_discs=total_discs,
                cover_data=cover_bytes,
            )

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 3:
        print("Usage: album_builder.py <album.json> <input_root>")
        sys.exit(1)
    json_path = Path(sys.argv[^6_1])
    input_root = Path(sys.argv[^6_2])
    process_album(json_path, input_root)
  • MutagenTagZugriff ist hier im FLACStil als dictInterface umgesetzt, wie in der Doku beschrieben.5857
  • Verzeichnisanlage nutzt Path.mkdir(parents=True, exist_ok=True), wie in üblichen BestPractices für verschachtelte Ordner gezeigt.5960

Wenn du mir ein konkretes JSON für ein reales Album und den aktuellen Speicherort deiner RohFiles schickst, passe ich dir Pfade, Dateinamensschema und TagMapping exakt darauf an. 6162636465666768697071


  1. https://nemp-help.gausi.de/de/Metadata.html ↩︎

  2. https://de.wikipedia.org/wiki/Vorbis_comment ↩︎

  3. https://www.reddit.com/r/jellyfin/comments/mtfg1p/jellyfin_music_metadatafolder_structure/ ↩︎

  4. https://www.reddit.com/r/jellyfin/comments/palkuy/love_it_but_help_please_tagging_metadata_and/ ↩︎

  5. https://www.mp3tag.de ↩︎

  6. https://www.mp3tag.de/en/ ↩︎

  7. https://products.documentprocessing.com/de/metadata/python/mutagen/ ↩︎

  8. https://products.documentprocessing.com/metadata/python/mutagen/ ↩︎

  9. https://mutagen.readthedocs.io ↩︎

  10. https://pypi.org/project/mutagen/ ↩︎

  11. https://community.mp3tag.de/t/mp3tag-fur-jellyfin/67818 ↩︎

  12. https://www.pcwelt.de/article/1151808/musicbrainz-picard-mp3-titelinfos-automatisch-vervollstaendigen.html ↩︎

  13. https://www.arkthinker.com/de/edit-audio/best-music-tag-editors/ ↩︎

  14. https://www.reddit.com/r/audiophile/comments/wozzir/auto_tagging_flac_files/ ↩︎

  15. https://www.reddit.com/r/ffmpeg/comments/ibhu89/editing_flac_and_mp3_metadata/ ↩︎

  16. https://jellyfin.org/docs/general/server/media/music/ ↩︎

  17. https://diymediaserver.com/post/how-proper-organization-helps-jellyfin-automatically-fetch-metadata-and-display-content-correctly/ ↩︎

  18. https://www.reddit.com/r/jellyfin/comments/o6ss8x/an_approach_to_tagging_collaboration_albums_for/ ↩︎

  19. https://github.com/jellyfin/jellyfin/issues/9359 ↩︎

  20. https://github.com/jellyfin/jellyfin/issues/2570 ↩︎

  21. https://www.reddit.com/r/jellyfin/comments/1p0vcev/missing_embedded_metadata_for_flac_music_library/ ↩︎

  22. https://www.reddit.com/r/audiophile/comments/wozzir/auto_tagging_flac_files/ ↩︎

  23. https://github.com/jellyfin/jellyfin/issues/11411 ↩︎

  24. https://www.reddit.com/r/jellyfin/comments/l8vhzv/using_playlistbased_music_folder_structure_and/ ↩︎

  25. https://www.reddit.com/r/jellyfin/comments/mtfg1p/jellyfin_music_metadatafolder_structure/ ↩︎

  26. https://www.reddit.com/r/jellyfin/comments/ikp2wc/help_me_to_organize_my_music_collection_for/ ↩︎

  27. https://www.reddit.com/r/JellyfinCommunity/comments/1k64mki/how_are_you_organizing_your_media_folders/ ↩︎

  28. https://www.reddit.com/r/jellyfin/comments/l4lpog/correct_media_folder_structure/ ↩︎

  29. https://www.reddit.com/r/jellyfin/comments/hfh1m1/music_metadata_without_modifying_files/ ↩︎

  30. https://www.youtube.com/watch?v=wBc7pZQ8bR0 ↩︎

  31. https://jellyfin.org/docs/general/server/media/music/ ↩︎

  32. https://www.reddit.com/r/jellyfin/comments/gif45f/music_metadata_good_practices_and_tips/ ↩︎

  33. https://www.reddit.com/r/selfhosted/comments/1ayt7z9/jellyfin_music_how_do_i_get_it_to_treat_singles/ ↩︎

  34. https://www.reddit.com/r/jellyfin/comments/l8vhzv/using_playlistbased_music_folder_structure_and/ ↩︎

  35. https://www.reddit.com/r/jellyfin/comments/mtfg1p/jellyfin_music_metadatafolder_structure/ ↩︎

  36. https://github.com/jellyfin/jellyfin/issues/2570 ↩︎

  37. https://www.reddit.com/r/jellyfin/comments/o6ss8x/an_approach_to_tagging_collaboration_albums_for/ ↩︎

  38. https://www.reddit.com/r/jellyfin/comments/1qronof/jellyfin_music_basics/ ↩︎

  39. https://github.com/jellyfin/jellyfin/issues/9359 ↩︎

  40. https://diymediaserver.com/post/how-proper-organization-helps-jellyfin-automatically-fetch-metadata-and-display-content-correctly/ ↩︎

  41. https://www.reddit.com/r/jellyfin/comments/1p0vcev/missing_embedded_metadata_for_flac_music_library/ ↩︎

  42. https://lemmy.world/post/42221496 ↩︎

  43. https://malidrive.com.tr/blog/enhance-musictag-genre-filtering-in ↩︎

  44. https://www.reddit.com/r/jellyfin/comments/z05w9h/music_artists_and_the_metadata/ ↩︎

  45. https://jellyfin.org/docs/general/server/metadata/nfo/ ↩︎

  46. https://www.reddit.com/r/jellyfin/comments/labgr2/is_there_a_way_to_use_a_folderfilesystem_view_for/ ↩︎

  47. https://www.reddit.com/r/jellyfin/comments/ikp2wc/help_me_to_organize_my_music_collection_for/ ↩︎

  48. https://www.youtube.com/watch?v=wBc7pZQ8bR0 ↩︎

  49. https://jellyfin.org/docs/general/server/media/music/ ↩︎

  50. https://www.reddit.com/r/jellyfin/comments/gif45f/music_metadata_good_practices_and_tips/ ↩︎

  51. https://github.com/jellyfin/jellyfin/issues/2570 ↩︎

  52. https://malidrive.com.tr/blog/enhance-musictag-genre-filtering-in ↩︎

  53. https://jellyfin.org/docs/general/server/media/music/ ↩︎

  54. https://www.reddit.com/r/jellyfin/comments/gif45f/music_metadata_good_practices_and_tips/ ↩︎

  55. https://github.com/jellyfin/jellyfin/issues/2570 ↩︎

  56. https://diymediaserver.com/post/how-proper-organization-helps-jellyfin-automatically-fetch-metadata-and-display-content-correctly/ ↩︎

  57. https://mutagen.readthedocs.io/en/latest/user/gettingstarted.html ↩︎

  58. https://linuxconfig.org/how-to-set-change-and-delete-music-tags-with-mutagen ↩︎

  59. https://www.geeksforgeeks.org/python/create-a-directory-in-python/ ↩︎

  60. https://realpython.com/working-with-files-in-python/ ↩︎

  61. https://www.reddit.com/r/jellyfin/comments/1054led/how_would_i_use_embedded_album_covers/ ↩︎

  62. https://stackoverflow.com/questions/50747484/removing-single-tag-from-audio-files-mp3-and-flac-python-mutagen ↩︎

  63. https://www.reddit.com/r/jellyfin/comments/oyvtu2/music_artwork_does_not_update_from_embedded_tag/ ↩︎

  64. https://stackoverflow.com/questions/12517451/automatically-creating-directories-with-file-output ↩︎

  65. https://mutagen.readthedocs.io ↩︎

  66. https://jellyfin.org/docs/general/server/media/music/ ↩︎

  67. https://www.geeksforgeeks.org/python/extract-and-add-flac-audio-metadata-using-the-mutagen-module-in-python/ ↩︎

  68. https://github.com/berdario/mutagen/blob/master/TUTORIAL ↩︎

  69. https://github.com/dropcreations/flactagger ↩︎

  70. https://github.com/jellyfin/jellyfin/issues/8570 ↩︎

  71. https://www.youtube.com/watch?v=I2wHz6Qm4Dg ↩︎