115 lines
6.6 KiB
Go
115 lines
6.6 KiB
Go
// Package subsonic implements the original Subsonic REST API (through
|
|
// version 1.16.1) on top of VibeSonic's existing database, scanner,
|
|
// streaming, and cover art packages. It does not duplicate business
|
|
// logic: every handler here is a thin adapter from Subsonic's wire
|
|
// format onto internal/database, internal/library, internal/streaming,
|
|
// and internal/coverart.
|
|
//
|
|
// One set of Go structs (this file and its model_*.go siblings) is
|
|
// shared between XML and JSON output via struct tags, so response
|
|
// shape can never drift between formats — see response.go for how they
|
|
// are serialized.
|
|
package subsonic
|
|
|
|
import "encoding/xml"
|
|
|
|
// ServerVersion is the highest Subsonic REST API version VibeSonic
|
|
// implements. Requests from a client claiming a newer protocol version
|
|
// are rejected (error code 20); older clients are accepted, since the
|
|
// protocol is additive.
|
|
const ServerVersion = "1.16.1"
|
|
|
|
// Response is the envelope every /rest/* call returns: exactly one of
|
|
// the payload fields below is set, matching the single child element
|
|
// real Subsonic servers emit inside <subsonic-response>.
|
|
type Response struct {
|
|
XMLName xml.Name `xml:"subsonic-response" json:"-"`
|
|
Xmlns string `xml:"xmlns,attr" json:"-"`
|
|
Status string `xml:"status,attr" json:"status"`
|
|
Version string `xml:"version,attr" json:"version"`
|
|
|
|
Error *Error `xml:"error,omitempty" json:"error,omitempty"`
|
|
|
|
License *License `xml:"license,omitempty" json:"license,omitempty"`
|
|
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
|
|
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
|
|
Directory *Directory `xml:"directory,omitempty" json:"directory,omitempty"`
|
|
Genres *Genres `xml:"genres,omitempty" json:"genres,omitempty"`
|
|
Artists *ArtistsID3 `xml:"artists,omitempty" json:"artists,omitempty"`
|
|
Artist *ArtistWithAlbumsID3 `xml:"artist,omitempty" json:"artist,omitempty"`
|
|
Album *AlbumWithSongsID3 `xml:"album,omitempty" json:"album,omitempty"`
|
|
Song *Child `xml:"song,omitempty" json:"song,omitempty"`
|
|
Videos *Videos `xml:"videos,omitempty" json:"videos,omitempty"`
|
|
VideoInfo *VideoInfo `xml:"videoInfo,omitempty" json:"videoInfo,omitempty"`
|
|
ArtistInfo *ArtistInfo `xml:"artistInfo,omitempty" json:"artistInfo,omitempty"`
|
|
ArtistInfo2 *ArtistInfo2 `xml:"artistInfo2,omitempty" json:"artistInfo2,omitempty"`
|
|
AlbumInfo *AlbumInfo `xml:"albumInfo,omitempty" json:"albumInfo,omitempty"`
|
|
SimilarSongs *SimilarSongs `xml:"similarSongs,omitempty" json:"similarSongs,omitempty"`
|
|
SimilarSongs2 *SimilarSongs2 `xml:"similarSongs2,omitempty" json:"similarSongs2,omitempty"`
|
|
TopSongs *TopSongs `xml:"topSongs,omitempty" json:"topSongs,omitempty"`
|
|
AlbumList *AlbumList `xml:"albumList,omitempty" json:"albumList,omitempty"`
|
|
AlbumList2 *AlbumList2 `xml:"albumList2,omitempty" json:"albumList2,omitempty"`
|
|
RandomSongs *Songs `xml:"randomSongs,omitempty" json:"randomSongs,omitempty"`
|
|
SongsByGenre *Songs `xml:"songsByGenre,omitempty" json:"songsByGenre,omitempty"`
|
|
NowPlaying *NowPlaying `xml:"nowPlaying,omitempty" json:"nowPlaying,omitempty"`
|
|
Starred *Starred `xml:"starred,omitempty" json:"starred,omitempty"`
|
|
Starred2 *Starred2 `xml:"starred2,omitempty" json:"starred2,omitempty"`
|
|
SearchResult *SearchResult `xml:"searchResult,omitempty" json:"searchResult,omitempty"`
|
|
SearchResult2 *SearchResult2 `xml:"searchResult2,omitempty" json:"searchResult2,omitempty"`
|
|
SearchResult3 *SearchResult3 `xml:"searchResult3,omitempty" json:"searchResult3,omitempty"`
|
|
Playlists *Playlists `xml:"playlists,omitempty" json:"playlists,omitempty"`
|
|
Playlist *PlaylistWithSongs `xml:"playlist,omitempty" json:"playlist,omitempty"`
|
|
JukeboxStatus *JukeboxStatus `xml:"jukeboxStatus,omitempty" json:"jukeboxStatus,omitempty"`
|
|
JukeboxPlaylist *JukeboxPlaylist `xml:"jukeboxPlaylist,omitempty" json:"jukeboxPlaylist,omitempty"`
|
|
InternetRadioStations *InternetRadioStations `xml:"internetRadioStations,omitempty" json:"internetRadioStations,omitempty"`
|
|
ChatMessages *ChatMessages `xml:"chatMessages,omitempty" json:"chatMessages,omitempty"`
|
|
User *User `xml:"user,omitempty" json:"user,omitempty"`
|
|
Users *Users `xml:"users,omitempty" json:"users,omitempty"`
|
|
Bookmarks *Bookmarks `xml:"bookmarks,omitempty" json:"bookmarks,omitempty"`
|
|
PlayQueue *PlayQueue `xml:"playQueue,omitempty" json:"playQueue,omitempty"`
|
|
Shares *Shares `xml:"shares,omitempty" json:"shares,omitempty"`
|
|
Podcasts *Podcasts `xml:"podcasts,omitempty" json:"podcasts,omitempty"`
|
|
NewestPodcasts *NewestPodcasts `xml:"newestPodcasts,omitempty" json:"newestPodcasts,omitempty"`
|
|
ScanStatus *ScanStatus `xml:"scanStatus,omitempty" json:"scanStatus,omitempty"`
|
|
Lyrics *Lyrics `xml:"lyrics,omitempty" json:"lyrics,omitempty"`
|
|
}
|
|
|
|
func newResponse() *Response {
|
|
return &Response{Xmlns: "http://subsonic.org/restapi", Status: "ok", Version: ServerVersion}
|
|
}
|
|
|
|
// Error is the payload of a failed response.
|
|
type Error struct {
|
|
Code int `xml:"code,attr" json:"code"`
|
|
Message string `xml:"message,attr" json:"message"`
|
|
}
|
|
|
|
// --- System ---
|
|
|
|
type License struct {
|
|
Valid bool `xml:"valid,attr" json:"valid"`
|
|
Email string `xml:"email,attr,omitempty" json:"email,omitempty"`
|
|
LicenseExpires string `xml:"licenseExpires,attr,omitempty" json:"licenseExpires,omitempty"`
|
|
}
|
|
|
|
// --- Music folders / genres ---
|
|
|
|
type MusicFolders struct {
|
|
MusicFolder []MusicFolder `xml:"musicFolder" json:"musicFolder"`
|
|
}
|
|
|
|
type MusicFolder struct {
|
|
ID string `xml:"id,attr" json:"id"`
|
|
Name string `xml:"name,attr" json:"name"`
|
|
}
|
|
|
|
type Genres struct {
|
|
Genre []Genre `xml:"genre" json:"genre"`
|
|
}
|
|
|
|
type Genre struct {
|
|
Name string `xml:",chardata" json:"value"`
|
|
SongCount int `xml:"songCount,attr" json:"songCount"`
|
|
AlbumCount int `xml:"albumCount,attr" json:"albumCount"`
|
|
}
|