1package models
2
3import "time"
4
5// ListenBrainzSubmission represents the top-level submission format
6type ListenBrainzSubmission struct {
7 ListenType string `json:"listen_type"`
8 Payload []ListenBrainzPayload `json:"payload"`
9}
10
11// ListenBrainzPayload represents individual listen data
12type ListenBrainzPayload struct {
13 ListenedAt *int64 `json:"listened_at,omitempty"`
14 TrackMetadata ListenBrainzTrackMetadata `json:"track_metadata"`
15}
16
17// ListenBrainzTrackMetadata contains the track information
18type ListenBrainzTrackMetadata struct {
19 ArtistName string `json:"artist_name"`
20 TrackName string `json:"track_name"`
21 ReleaseName *string `json:"release_name,omitempty"`
22 AdditionalInfo *ListenBrainzAdditionalInfo `json:"additional_info,omitempty"`
23}
24
25// ListenBrainzAdditionalInfo contains optional metadata
26type ListenBrainzAdditionalInfo struct {
27 MediaPlayer *string `json:"media_player,omitempty"`
28 SubmissionClient *string `json:"submission_client,omitempty"`
29 SubmissionClientVersion *string `json:"submission_client_version,omitempty"`
30 RecordingMBID *string `json:"recording_mbid,omitempty"`
31 ArtistMBIDs []string `json:"artist_mbids,omitempty"`
32 ReleaseMBID *string `json:"release_mbid,omitempty"`
33 ReleaseGroupMBID *string `json:"release_group_mbid,omitempty"`
34 TrackMBID *string `json:"track_mbid,omitempty"`
35 WorkMBIDs []string `json:"work_mbids,omitempty"`
36 Tags []string `json:"tags,omitempty"`
37 DurationMs *int64 `json:"duration_ms,omitempty"`
38 SpotifyID *string `json:"spotify_id,omitempty"`
39 ISRC *string `json:"isrc,omitempty"`
40 TrackNumber *int `json:"tracknumber,omitempty"`
41 DiscNumber *int `json:"discnumber,omitempty"`
42 MusicService *string `json:"music_service,omitempty"`
43 MusicServiceName *string `json:"music_service_name,omitempty"`
44 OriginURL *string `json:"origin_url,omitempty"`
45 LastFMTrackURL *string `json:"lastfm_track_url,omitempty"`
46 YoutubeID *string `json:"youtube_id,omitempty"`
47}
48
49// ConvertToTrack converts ListenBrainz format to internal Track format
50func (lbp *ListenBrainzPayload) ConvertToTrack(userID int64) Track {
51 track := Track{
52 Name: lbp.TrackMetadata.TrackName,
53 Artist: []Artist{{Name: lbp.TrackMetadata.ArtistName}},
54 }
55
56 // Set timestamp
57 if lbp.ListenedAt != nil {
58 track.Timestamp = time.Unix(*lbp.ListenedAt, 0)
59 } else {
60 track.Timestamp = time.Now()
61 }
62
63 // Set album/release name
64 if lbp.TrackMetadata.ReleaseName != nil {
65 track.Album = *lbp.TrackMetadata.ReleaseName
66 }
67
68 // Handle additional info if present
69 if info := lbp.TrackMetadata.AdditionalInfo; info != nil {
70 // Set MBIDs
71 if info.RecordingMBID != nil {
72 track.RecordingMBID = info.RecordingMBID
73 }
74 if info.ReleaseMBID != nil {
75 track.ReleaseMBID = info.ReleaseMBID
76 }
77
78 // Set duration
79 if info.DurationMs != nil {
80 track.DurationMs = *info.DurationMs
81 }
82
83 // Set ISRC
84 if info.ISRC != nil {
85 track.ISRC = *info.ISRC
86 }
87
88 // Handle multiple artists from MBIDs
89 if len(info.ArtistMBIDs) > 0 {
90 artists := make([]Artist, len(info.ArtistMBIDs))
91 for i, mbid := range info.ArtistMBIDs {
92 artists[i] = Artist{
93 Name: lbp.TrackMetadata.ArtistName, // Use main artist name
94 MBID: &mbid,
95 }
96 }
97 track.Artist = artists
98 }
99
100 // Set service information
101 if info.MusicService != nil {
102 track.ServiceBaseUrl = *info.MusicService
103 }
104 if info.OriginURL != nil {
105 track.URL = *info.OriginURL
106 }
107 if info.SpotifyID != nil {
108 track.URL = "https://open.spotify.com/track/" + *info.SpotifyID
109 track.ServiceBaseUrl = "spotify"
110 }
111 }
112
113 // Default service if not set
114 if track.ServiceBaseUrl == "" {
115 track.ServiceBaseUrl = "listenbrainz"
116 }
117
118 // Mark as stamped since it came from external submission
119 track.HasStamped = true
120
121 return track
122}