From e9fbd044d0a9c5d26f14828fca8c75a26ca982b9 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Wed, 15 Apr 2026 22:33:36 +0200 Subject: [PATCH] trimmed down metadata & own extractor for vobis(flac) --- internal/metadata/metadata.go | 32 +++++++---- internal/metadata/vobis.go | 103 +++++++++++++++++++++++++++++++--- internal/ripsort.go | 1 - internal/sorter.go | 19 ++++--- 4 files changed, 127 insertions(+), 28 deletions(-) diff --git a/internal/metadata/metadata.go b/internal/metadata/metadata.go index 7e62ad7..9e794e8 100644 --- a/internal/metadata/metadata.go +++ b/internal/metadata/metadata.go @@ -11,18 +11,27 @@ import ( ) type Metadata struct { - Title string + Title *string Artist []string - Album string + Album *string AlbumArtist []string Track int TotalTracks int - Disc int - TotalDiscs int - Comment string + Comment *string } func ReadAudioTags(filePath string) (*Metadata, error) { + ext := strings.ToLower(filepath.Ext(filePath)) + + switch { + case ext == ".flac": + return readVorbisMetadata(filePath) + default: + return readGenericAudioTags(filePath) + } +} + +func readGenericAudioTags(filePath string) (*Metadata, error) { f, err := os.Open(filePath) if err != nil { return nil, fmt.Errorf("failed to open file: %w", err) @@ -35,18 +44,19 @@ func ReadAudioTags(filePath string) (*Metadata, error) { } track, totalTracks := m.Track() - disc, totalDiscs := m.Disc() + + title := m.Title() + album := m.Album() + comment := m.Comment() info := &Metadata{ - Title: m.Title(), + Title: &title, Artist: parseSeperatedTag(m.Artist()), - Album: m.Album(), + Album: &album, AlbumArtist: parseSeperatedTag(m.AlbumArtist()), Track: track, TotalTracks: totalTracks, - Disc: disc, - TotalDiscs: totalDiscs, - Comment: m.Comment(), + Comment: &comment, } return info, nil diff --git a/internal/metadata/vobis.go b/internal/metadata/vobis.go index 116b35f..1c9b78b 100644 --- a/internal/metadata/vobis.go +++ b/internal/metadata/vobis.go @@ -2,12 +2,89 @@ package metadata import ( "log/slog" + "os" "strconv" "github.com/go-flac/flacvorbis/v2" "github.com/go-flac/go-flac/v2" ) +func readVorbisMetadata(file string) (*Metadata, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + + defer f.Close() + + flacFile, err := flac.ParseMetadata(f) + if err != nil { + return nil, err + } + + cmt, err := findVobisMetadata(*flacFile) + if err != nil { + return nil, err + } + + titles, err := cmt.Get(flacvorbis.FIELD_TITLE) + if err != nil { + return nil, err + } + var title *string + if len(titles) > 0 { + title = &titles[0] + } + + albums, err := cmt.Get(flacvorbis.FIELD_ALBUM) + if err != nil { + return nil, err + } + var album *string + if len(albums) > 0 { + album = &albums[0] + } + + artists, err := cmt.Get(flacvorbis.FIELD_ARTIST) + if err != nil { + return nil, err + } + + albumArtists, err := cmt.Get("ALBUMARTIST") + if err != nil { + return nil, err + } + + comments, err := cmt.Get("COMMENT") + if err != nil { + return nil, err + } + var comment *string + if len(comments) > 0 { + comment = &comments[0] + } + + metadata := &Metadata{ + Title: title, + Artist: artists, + Album: album, + AlbumArtist: albumArtists, + Comment: comment, + } + + return metadata, nil +} + +func findVobisMetadata(f flac.File) (*flacvorbis.MetaDataBlockVorbisComment, error) { + for _, meta := range f.Meta { + if meta.Type == flac.VorbisComment { + return flacvorbis.ParseFromMetaDataBlock(*meta) + } + } + + return nil, nil +} + func updateFlacMetadata(m Metadata, input, output string) error { f, err := flac.ParseFile(input) if err != nil { @@ -36,13 +113,25 @@ func updateFlacMetadata(m Metadata, input, output string) error { func createVorbisMetaBlock(m Metadata) flacvorbis.MetaDataBlockVorbisComment { vorbisMeta := flacvorbis.New() - vorbisMeta.Add(flacvorbis.FIELD_TITLE, m.Title) - vorbisMeta.Add(flacvorbis.FIELD_ALBUM, m.Album) - vorbisMeta.Add("COMMENT", m.Comment) - vorbisMeta.Add("TRACKNUMBER", strconv.Itoa(m.Track)) - vorbisMeta.Add("TOTALTRACKS", strconv.Itoa(m.TotalTracks)) - vorbisMeta.Add("DISCNUMBER", strconv.Itoa(m.Disc)) - vorbisMeta.Add("TOTALDISCS", strconv.Itoa(m.TotalDiscs)) + if m.Title != nil { + vorbisMeta.Add(flacvorbis.FIELD_TITLE, *m.Title) + } + + if m.Album != nil { + vorbisMeta.Add(flacvorbis.FIELD_ALBUM, *m.Album) + } + + if m.Comment != nil { + vorbisMeta.Add("COMMENT", *m.Comment) + } + + if m.Track != 0 { + vorbisMeta.Add("TRACKNUMBER", strconv.Itoa(m.Track)) + } + + if m.TotalTracks != 0 { + vorbisMeta.Add("TOTALTRACKS", strconv.Itoa(m.TotalTracks)) + } for _, artist := range m.Artist { vorbisMeta.Add(flacvorbis.FIELD_ARTIST, artist) diff --git a/internal/ripsort.go b/internal/ripsort.go index 825aaf4..7a9ef71 100644 --- a/internal/ripsort.go +++ b/internal/ripsort.go @@ -23,7 +23,6 @@ func Scan(filePath string) { fmt.Printf("Album: %s\n", info.Album) fmt.Printf("Album Artist: %s\n", info.AlbumArtist) fmt.Printf("Track: %d/%d\n", info.Track, info.TotalTracks) - fmt.Printf("Disc: %d/%d\n", info.Disc, info.TotalDiscs) fmt.Printf("Comment: %s\n", info.Comment) sortPath := pathForFile(filePath, *info) diff --git a/internal/sorter.go b/internal/sorter.go index 5a030de..3cdebe3 100644 --- a/internal/sorter.go +++ b/internal/sorter.go @@ -61,33 +61,33 @@ func sortSong(src, dst string, updateMeta bool) error { return nil } -func sanitizeName(name string) *string { - if name == "" { +func sanitizeName(name *string) *string { + if name == nil || *name == "" { return nil } re := regexp.MustCompile(`[<>:"/\\|?*\x00-\x1F]`) - name = re.ReplaceAllString(name, "_") + dName := re.ReplaceAllString(*name, "_") - name = strings.Trim(name, " .") + dName = strings.Trim(dName, " .") - if name == "" { + if dName == "" { return nil } - return &name + return &dName } func getArtistName(m metadata.Metadata) string { var artist *string if len(m.Artist) > 0 { - artist = sanitizeName(m.Artist[0]) + artist = sanitizeName(&m.Artist[0]) } if artist == nil && len(m.AlbumArtist) > 0 { if aa := m.AlbumArtist[0]; aa != "" { - artist = sanitizeName(aa) + artist = sanitizeName(&aa) } } @@ -109,7 +109,8 @@ func getAlbumName(m metadata.Metadata) string { func getTitle(src string, m metadata.Metadata) string { title := sanitizeName(m.Title) if title == nil { - return *sanitizeName(strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))) + filename := strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) + return *sanitizeName(&filename) } return *title }