package musicbrainz import ( "fmt" "time" "github.com/metadata-agregator/internal/domain" ) func mapArtist(mb *mbArtist) *domain.Artist { if mb == nil { return nil } artist := &domain.Artist{ ID: mb.ID, Name: mb.Name, SortName: mb.SortName, Type: mb.Type, Country: mb.Country, Description: mb.Disambiguation, ExternalIDs: []domain.ExternalID{{ Source: "musicbrainz", SourceID: mb.ID, URL: fmt.Sprintf("https://musicbrainz.org/artist/%s", mb.ID), }}, } if mb.LifeSpan.Begin != "" { if t := parseDate(mb.LifeSpan.Begin); t != nil { artist.FormedDate = t } } if mb.LifeSpan.End != "" { if t := parseDate(mb.LifeSpan.End); t != nil { artist.DisbandedDate = t } } for _, g := range mb.Genres { artist.Genres = append(artist.Genres, domain.Genre{ ID: g.ID, Name: g.Name, }) } for _, rel := range mb.Relations { if rel.Type == "image" && rel.URL != nil { artist.ImageURL = rel.URL.Resource break } } return artist } func mapAlbum(mb *mbReleaseGroup, release *mbRelease) *domain.Album { if mb == nil { return nil } album := &domain.Album{ ID: mb.ID, Title: mb.Title, Type: mb.PrimaryType, ExternalIDs: []domain.ExternalID{{ Source: "musicbrainz", SourceID: mb.ID, URL: fmt.Sprintf("https://musicbrainz.org/release-group/%s", mb.ID), }}, } if mb.FirstReleaseDate != "" { album.ReleaseDate = parseDate(mb.FirstReleaseDate) } for _, ac := range mb.ArtistCredit { album.Artists = append(album.Artists, mapArtistCredit(&ac, "primary")) } for _, g := range mb.Genres { album.Genres = append(album.Genres, domain.Genre{ ID: g.ID, Name: g.Name, }) } if release != nil { album.UPC = release.Barcode if len(release.LabelInfo) > 0 && release.LabelInfo[0].Label != nil { album.Label = mapLabel(release.LabelInfo[0].Label) } for _, m := range release.Media { album.TotalTracks += m.TrackCount } album.TotalDiscs = len(release.Media) if release.CoverArtArchive.Front { album.CoverURL = fmt.Sprintf("https://coverartarchive.org/release/%s/front", release.ID) } } return album } func mapTrack(mb *mbRecording, discNum, trackNum int) *domain.Track { if mb == nil { return nil } track := &domain.Track{ ID: mb.ID, Title: mb.Title, DurationMs: mb.Length, DiscNumber: discNum, TrackNumber: trackNum, ExternalIDs: []domain.ExternalID{{ Source: "musicbrainz", SourceID: mb.ID, URL: fmt.Sprintf("https://musicbrainz.org/recording/%s", mb.ID), }}, } if len(mb.ISRCs) > 0 { track.ISRC = mb.ISRCs[0] } for _, ac := range mb.ArtistCredit { track.Artists = append(track.Artists, mapArtistCredit(&ac, "primary")) } for _, rel := range mb.Relations { if rel.TargetType == "work" && rel.Work != nil { track.Work = mapWork(rel.Work) break } } return track } func mapWork(mb *mbWork) *domain.Work { if mb == nil { return nil } work := &domain.Work{ ID: mb.ID, Title: mb.Title, Type: mb.Type, Language: mb.Language, } for _, rel := range mb.Relations { if rel.TargetType == "artist" && rel.Artist != nil { role := "writer" if rel.Type == "composer" || rel.Type == "lyricist" || rel.Type == "writer" { role = rel.Type } work.Composers = append(work.Composers, domain.ArtistCredit{ Artist: *mapArtist(rel.Artist), Role: role, }) } } return work } func mapLabel(mb *mbLabel) *domain.Label { if mb == nil { return nil } return &domain.Label{ ID: mb.ID, Name: mb.Name, Country: mb.Country, } } func mapArtistCredit(ac *mbArtistCredit, defaultRole string) domain.ArtistCredit { credit := domain.ArtistCredit{ Role: defaultRole, JoinPhrase: ac.JoinPhrase, } if ac.Artist != nil { credit.Artist = *mapArtist(ac.Artist) } return credit } func parseDate(s string) *time.Time { formats := []string{ "2006-01-02", "2006-01", "2006", } for _, f := range formats { if t, err := time.Parse(f, s); err == nil { return &t } } return nil }