package coverart import ( "errors" "fmt" "os" "github.com/dhowden/tag" ) // ErrNoEmbeddedArt indicates the audio file has no embedded picture. // Distinct from "tag read failed" so the enricher can quietly fall // through to the provider chain without logging at warn/error level. var ErrNoEmbeddedArt = errors.New("coverart: no embedded album art") // ExtractEmbeddedAlbumArt reads the embedded picture from an audio // file's tag block: ID3v2 APIC frames (MP3), FLAC // METADATA_BLOCK_PICTURE blocks, MP4 covr atoms (M4A/M4B/AAC), and OGG // METADATA_BLOCK_PICTURE base64 in vorbis comments. Whichever format // dhowden/tag recognises. // // Returns ErrNoEmbeddedArt when the tag block parses but contains no // usable picture; returns a wrapped error for I/O or tag-parse // failures so callers can distinguish "no art" from "couldn't read". // // Picard- and Lidarr-tagged libraries typically carry the canonical // art in this block already — extracting it beats every external API // guess for accuracy and avoids a network round-trip. func ExtractEmbeddedAlbumArt(path string) ([]byte, error) { f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("open: %w", err) } defer func() { _ = f.Close() }() meta, err := tag.ReadFrom(f) if err != nil { return nil, fmt.Errorf("tag read: %w", err) } pic := meta.Picture() if pic == nil || len(pic.Data) == 0 { return nil, ErrNoEmbeddedArt } return pic.Data, nil }