From 68b2e649f0e217d4402670c9cb0bc367d1d2752d Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Thu, 23 Nov 2023 08:28:17 +0100 Subject: [PATCH] JSPF: Include full LB additional info in metadata --- backends/jspf/jspf.go | 33 +++++++++++++++++++-------------- models/models.go | 42 ++++++++++++++++++++++++++++++++++++++++++ models/models_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 14 deletions(-) diff --git a/backends/jspf/jspf.go b/backends/jspf/jspf.go index e5de6f9..797cf2c 100644 --- a/backends/jspf/jspf.go +++ b/backends/jspf/jspf.go @@ -75,29 +75,31 @@ func (b *JSPFBackend) ImportLoves(export models.LovesResult, importResult models return importResult, nil } -func listenAsTrack(listen models.Listen) Track { - track := trackAsTrack(listen.Track) - extension := makeMusicBrainzExtension(listen.Track) - extension.AddedAt = listen.ListenedAt - extension.AddedBy = listen.UserName +func listenAsTrack(l models.Listen) Track { + l.FillAdditionalInfo() + track := trackAsTrack(l.Track) + extension := makeMusicBrainzExtension(l.Track) + extension.AddedAt = l.ListenedAt + extension.AddedBy = l.UserName track.Extension[MusicBrainzTrackExtensionId] = extension - if listen.RecordingMbid != "" { - track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(listen.RecordingMbid)) + if l.RecordingMbid != "" { + track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(l.RecordingMbid)) } return track } -func loveAsTrack(love models.Love) Track { - track := trackAsTrack(love.Track) - extension := makeMusicBrainzExtension(love.Track) - extension.AddedAt = love.Created - extension.AddedBy = love.UserName +func loveAsTrack(l models.Love) Track { + l.FillAdditionalInfo() + track := trackAsTrack(l.Track) + extension := makeMusicBrainzExtension(l.Track) + extension.AddedAt = l.Created + extension.AddedBy = l.UserName track.Extension[MusicBrainzTrackExtensionId] = extension - if love.RecordingMbid != "" { - track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(love.RecordingMbid)) + if l.RecordingMbid != "" { + track.Identifier = append(track.Identifier, "https://musicbrainz.org/recording/"+string(l.RecordingMbid)) } return track @@ -129,6 +131,9 @@ func makeMusicBrainzExtension(t models.Track) MusicBrainzTrackExtension { extension.ReleaseIdentifier = "https://musicbrainz.org/release/" + string(t.ReleaseMbid) } + // The tracknumber tag would be redundant + delete(extension.AdditionalMetadata, "tracknumber") + return extension } diff --git a/models/models.go b/models/models.go index 2f2e2e4..7500759 100644 --- a/models/models.go +++ b/models/models.go @@ -51,6 +51,48 @@ func (t Track) ArtistName() string { return strings.Join(t.ArtistNames, ", ") } +// Updates AdditionalInfo to have standard fields as defined by ListenBrainz +func (t *Track) FillAdditionalInfo() { + if t.AdditionalInfo == nil { + t.AdditionalInfo = make(AdditionalInfo, 5) + } + if t.RecordingMbid != "" { + t.AdditionalInfo["recording_mbid"] = t.RecordingMbid + } + if t.ReleaseGroupMbid != "" { + t.AdditionalInfo["release_group_mbid"] = t.ReleaseGroupMbid + } + if t.ReleaseMbid != "" { + t.AdditionalInfo["release_mbid"] = t.ReleaseMbid + } + if len(t.ArtistMbids) > 0 { + t.AdditionalInfo["artist_mbids"] = t.ArtistMbids + } + if len(t.WorkMbids) > 0 { + t.AdditionalInfo["work_mbids"] = t.WorkMbids + } + if t.ISRC != "" { + t.AdditionalInfo["isrc"] = t.ISRC + } + if t.TrackNumber != 0 { + t.AdditionalInfo["tracknumber"] = t.TrackNumber + } + if t.DiscNumber != 0 { + t.AdditionalInfo["discnumber"] = t.DiscNumber + } + if t.Duration != 0 { + rounded := t.Duration.Round(time.Second) + if t.Duration == rounded { + t.AdditionalInfo["duration"] = int64(t.Duration.Seconds()) + } else { + t.AdditionalInfo["duration_ms"] = t.Duration.Milliseconds() + } + } + if len(t.Tags) > 0 { + t.AdditionalInfo["tags"] = t.Tags + } +} + type Listen struct { Track ListenedAt time.Time diff --git a/models/models_test.go b/models/models_test.go index b6dc0ca..994cd68 100644 --- a/models/models_test.go +++ b/models/models_test.go @@ -42,6 +42,45 @@ func TestTrackArtistName(t *testing.T) { assert.Equal(t, "Foo, Bar, Baz", track.ArtistName()) } +func TestTrackFillAdditionalInfo(t *testing.T) { + track := models.Track{ + RecordingMbid: models.MBID("c0a1fc94-5f04-4a5f-bc09-e5de0c49cd12"), + ReleaseGroupMbid: models.MBID("80aca1ee-aa51-41be-9f75-024710d92ff4"), + ReleaseMbid: models.MBID("aa1ea1ac-7ec4-4542-a494-105afbfe547d"), + ArtistMbids: []models.MBID{"24412926-c7bd-48e8-afad-8a285b42e131"}, + WorkMbids: []models.MBID{"c0a1fc94-5f04-4a5f-bc09-e5de0c49cd12"}, + TrackNumber: 5, + DiscNumber: 1, + Duration: time.Duration(413787 * time.Millisecond), + ISRC: "DES561620801", + Tags: []string{"rock", "psychedelic rock"}, + } + track.FillAdditionalInfo() + i := track.AdditionalInfo + assert := assert.New(t) + assert.Equal(track.RecordingMbid, i["recording_mbid"]) + assert.Equal(track.ReleaseGroupMbid, i["release_group_mbid"]) + assert.Equal(track.ReleaseMbid, i["release_mbid"]) + assert.Equal(track.ArtistMbids, i["artist_mbids"]) + assert.Equal(track.WorkMbids, i["work_mbids"]) + assert.Equal(track.TrackNumber, i["tracknumber"]) + assert.Equal(track.DiscNumber, i["discnumber"]) + assert.Equal(track.Duration.Milliseconds(), i["duration_ms"]) + assert.Equal(track.ISRC, i["isrc"]) + assert.Equal(track.Tags, i["tags"]) +} + +func TestTrackFillAdditionalInfoRoundSecond(t *testing.T) { + ts := models.Track{Duration: time.Duration(123000 * time.Millisecond)} + ts.FillAdditionalInfo() + assert.Equal(t, int64(123), ts.AdditionalInfo["duration"]) + assert.Equal(t, nil, ts.AdditionalInfo["duration_ms"]) + tms := models.Track{Duration: time.Duration(123001 * time.Millisecond)} + tms.FillAdditionalInfo() + assert.Equal(t, nil, tms.AdditionalInfo["duration"]) + assert.Equal(t, int64(123001), tms.AdditionalInfo["duration_ms"]) +} + func TestListensListNewerThan(t *testing.T) { listen1 := models.Listen{ListenedAt: time.Unix(3, 0)} listen2 := models.Listen{ListenedAt: time.Unix(0, 0)}