package library import ( "strings" "github.com/dhowden/tag" "github.com/dhowden/tag/mbz" ) // extractMBIDs reads MusicBrainz album and artist IDs from a tag.Metadata. // // Delegates to dhowden/tag/mbz, which knows the per-format Raw() conventions: // - Vorbis (FLAC/OGG) keys are lowercased by the parser. // - ID3v2 (MP3) TXXX frames are stored under "TXXX"/"TXXX_N" with // a *tag.Comm value whose Description holds the Picard tag name. // - MP4 (M4A) freeform iTunes atoms are stored under their bare sub-name. // // Then sanitizes: dhowden's readTextWithDescrFrame (used for ID3v2 TXXX) // does NOT strip the trailing/embedded NUL bytes that ID3v2.4 uses as // frame terminator and multi-value separator — so the Text often comes // out as "uuid\x00" or "uuid1\x00uuid2". Postgres rejects NULs in text // columns (SQLSTATE 22021). We split on NUL and take the first non-empty // segment — Minstrel uses the primary release artist for MBCAA lookup, // so first-wins matches the original semantics. func extractMBIDs(m tag.Metadata) (albumMBID, artistMBID string) { info := mbz.Extract(m) return cleanMBID(info.Get(mbz.Album)), cleanMBID(info.Get(mbz.Artist)) } // extractRecordingMBID reads the MusicBrainz *recording* ID — Picard's // musicbrainz_recordingid, surfaced by dhowden/tag as mbz.Recording // (tag display name "MusicBrainz Track Id"). This is the id the // ListenBrainz Labs similar-recordings API keys on and what tracks.mbid // stores. // // Deliberately NOT mbz.Track ("MusicBrainz Release Track Id"): that is // per-release-track, whereas similarity is per-recording. Kept separate // from extractMBIDs so its existing (album, artist) signature and unit // tests stay untouched. func extractRecordingMBID(m tag.Metadata) string { return cleanMBID(mbz.Extract(m).Get(mbz.Recording)) } func cleanMBID(s string) string { if s == "" { return "" } for _, part := range strings.Split(s, "\x00") { if t := strings.TrimSpace(part); t != "" { return t } } return "" }