package subsonic import ( "time" "github.com/benya/temporserv/internal/library" "github.com/benya/temporserv/internal/scanner" ) type Envelope struct { SubsonicResponse Response `json:"subsonic-response"` } type Response struct { Status string `json:"status"` Version string `json:"version"` Type string `json:"type"` Server string `json:"serverVersion"` OpenAPI bool `json:"openSubsonic"` Artists []ArtistRef `json:"artists,omitempty"` Artist *ArtistFull `json:"artist,omitempty"` Album *AlbumFull `json:"album,omitempty"` Song *SongFull `json:"song,omitempty"` RandomSong []SongRef `json:"randomSongs,omitempty"` ScanStatus *ScanStatus `json:"scanStatus,omitempty"` Error *ErrorRef `json:"error,omitempty"` } type ArtistRef struct { ID string `json:"id"` Name string `json:"name"` } type SongRef struct { ID string `json:"id"` Title string `json:"title"` Album string `json:"album"` Artist string `json:"artist"` } type ArtistFull struct { ID string `json:"id"` Name string `json:"name"` CoverArt string `json:"coverArt,omitempty"` AlbumCount int `json:"albumCount,omitempty"` Albums []AlbumRef `json:"album,omitempty"` } type AlbumRef struct { ID string `json:"id"` Name string `json:"name"` Artist string `json:"artist"` ArtistID string `json:"artistId"` Year int `json:"year,omitempty"` CoverArt string `json:"coverArt,omitempty"` } type AlbumFull struct { ID string `json:"id"` Name string `json:"name"` Artist string `json:"artist"` ArtistID string `json:"artistId"` Year int `json:"year,omitempty"` CoverArt string `json:"coverArt,omitempty"` Song []SongRef `json:"song,omitempty"` } type SongFull struct { ID string `json:"id"` Title string `json:"title"` Album string `json:"album"` Artist string `json:"artist"` AlbumID string `json:"albumId"` ArtistID string `json:"artistId"` Track int `json:"track,omitempty"` Duration int `json:"duration,omitempty"` CoverArt string `json:"coverArt,omitempty"` } type ScanStatus struct { Scanning bool `json:"scanning"` Count int `json:"count"` FolderCount int `json:"folderCount"` LastError string `json:"lastError,omitempty"` StartedAt string `json:"startedAt,omitempty"` FinishedAt string `json:"finishedAt,omitempty"` } type ErrorRef struct { Code int `json:"code"` Message string `json:"message"` } func PingResponse() Envelope { return Envelope{ SubsonicResponse: Response{ Status: "ok", Version: "1.16.1", Type: "temporserv", Server: "0.1.0", OpenAPI: true, }, } } func ArtistsResponse(artists []library.Artist) Envelope { response := PingResponse() for _, artist := range artists { response.SubsonicResponse.Artists = append(response.SubsonicResponse.Artists, ArtistRef{ ID: artist.ID, Name: artist.Name, }) } return response } func RandomSongsResponse(tracks []library.Track) Envelope { response := PingResponse() for _, track := range tracks { response.SubsonicResponse.RandomSong = append(response.SubsonicResponse.RandomSong, SongRef{ ID: track.ID, Title: track.Title, Album: track.AlbumTitle, Artist: track.ArtistName, }) } return response } func ArtistResponse(artist library.ArtistDetail) Envelope { response := PingResponse() item := &ArtistFull{ ID: artist.ID, Name: artist.Name, CoverArt: artist.CoverArtID, AlbumCount: artist.AlbumCount, } for _, album := range artist.Albums { item.Albums = append(item.Albums, AlbumRef{ ID: album.ID, Name: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, CoverArt: album.CoverArtID, }) } response.SubsonicResponse.Artist = item return response } func AlbumResponse(album library.AlbumDetail) Envelope { response := PingResponse() item := &AlbumFull{ ID: album.ID, Name: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, CoverArt: album.CoverArtID, } for _, track := range album.Tracks { item.Song = append(item.Song, SongRef{ ID: track.ID, Title: track.Title, Album: track.AlbumTitle, Artist: track.ArtistName, }) } response.SubsonicResponse.Album = item return response } func SongResponse(track library.Track) Envelope { response := PingResponse() response.SubsonicResponse.Song = &SongFull{ ID: track.ID, Title: track.Title, Album: track.AlbumTitle, Artist: track.ArtistName, AlbumID: track.AlbumID, ArtistID: track.ArtistID, Track: track.TrackNumber, Duration: track.DurationSecs, CoverArt: track.CoverArtID, } return response } func ScanStatusResponse(status scanner.Status) Envelope { response := PingResponse() response.SubsonicResponse.ScanStatus = &ScanStatus{ Scanning: status.Scanning, Count: status.Tracks, FolderCount: status.Albums, LastError: status.LastError, StartedAt: formatTime(status.StartedAt), FinishedAt: formatTime(status.FinishedAt), } return response } func ErrorResponse(code int, message string) Envelope { response := PingResponse() response.SubsonicResponse.Status = "failed" response.SubsonicResponse.Error = &ErrorRef{ Code: code, Message: message, } return response } func formatTime(value time.Time) string { if value.IsZero() { return "" } return value.Format(time.RFC3339) }