1package spec
2
3import (
4	"fmt"
5	"time"
6
7	"senan.xyz/g/gonic/version"
8)
9
10var (
11	apiVersion = "1.9.0"
12	xmlns      = "http://subsonic.org/restapi"
13)
14
15type Response struct {
16	Status            string             `xml:"status,attr"       json:"status"`
17	Version           string             `xml:"version,attr"      json:"version"`
18	XMLNS             string             `xml:"xmlns,attr"        json:"-"`
19	Type              string             `xml:"type,attr"         json:"type"`
20	GonicVersion      string             `xml:"gonicVersion,attr" json:"gonicVersion"`
21	Error             *Error             `xml:"error"             json:"error,omitempty"`
22	Albums            *Albums            `xml:"albumList"         json:"albumList,omitempty"`
23	AlbumsTwo         *Albums            `xml:"albumList2"        json:"albumList2,omitempty"`
24	Album             *Album             `xml:"album"             json:"album,omitempty"`
25	Track             *TrackChild        `xml:"song"              json:"song,omitempty"`
26	Indexes           *Indexes           `xml:"indexes"           json:"indexes,omitempty"`
27	Artists           *Artists           `xml:"artists"           json:"artists,omitempty"`
28	Artist            *Artist            `xml:"artist"            json:"artist,omitempty"`
29	Directory         *Directory         `xml:"directory"         json:"directory,omitempty"`
30	RandomTracks      *RandomTracks      `xml:"randomSongs"       json:"randomSongs,omitempty"`
31	TracksByGenre     *TracksByGenre     `xml:"songsByGenre"      json:"songsByGenre,omitempty"`
32	MusicFolders      *MusicFolders      `xml:"musicFolders"      json:"musicFolders,omitempty"`
33	ScanStatus        *ScanStatus        `xml:"scanStatus"        json:"scanStatus,omitempty"`
34	Licence           *Licence           `xml:"license"           json:"license,omitempty"`
35	SearchResultTwo   *SearchResultTwo   `xml:"searchResult2"     json:"searchResult2,omitempty"`
36	SearchResultThree *SearchResultThree `xml:"searchResult3"     json:"searchResult3,omitempty"`
37	User              *User              `xml:"user"              json:"user,omitempty"`
38	Playlists         *Playlists         `xml:"playlists"         json:"playlists,omitempty"`
39	Playlist          *Playlist          `xml:"playlist"          json:"playlist,omitempty"`
40	ArtistInfo        *ArtistInfo        `xml:"artistInfo"        json:"artistInfo,omitempty"`
41	ArtistInfoTwo     *ArtistInfo        `xml:"artistInfo2"       json:"artistInfo2,omitempty"`
42	Genres            *Genres            `xml:"genres"            json:"genres,omitempty"`
43	PlayQueue         *PlayQueue         `xml:"playQueue"         json:"playQueue,omitempty"`
44}
45
46func NewResponse() *Response {
47	return &Response{
48		Status:       "ok",
49		XMLNS:        xmlns,
50		Version:      apiVersion,
51		Type:         version.NAME,
52		GonicVersion: version.VERSION,
53	}
54}
55
56// spec errors:
57//  0  a generic error
58// 10  required parameter is missing
59// 20  incompatible subsonic rest protocol version. client must upgrade
60// 30  incompatible subsonic rest protocol version. server must upgrade
61// 40  wrong username or password
62// 41  token authentication not supported for ldap users
63// 50  user is not authorized for the given operation
64// 60  the trial period for the subsonic server is over
65// 70  the requested data was not found
66type Error struct {
67	Code    int    `xml:"code,attr"    json:"code"`
68	Message string `xml:"message,attr" json:"message"`
69}
70
71func NewError(code int, message string, a ...interface{}) *Response {
72	return &Response{
73		Status:  "failed",
74		XMLNS:   xmlns,
75		Version: apiVersion,
76		Error: &Error{
77			Code:    code,
78			Message: fmt.Sprintf(message, a...),
79		},
80		Type:         version.NAME,
81		GonicVersion: version.VERSION,
82	}
83}
84
85type Albums struct {
86	List []*Album `xml:"album" json:"album"`
87}
88
89type Album struct {
90	// common
91	ID       int    `xml:"id,attr,omitempty"       json:"id,string"`
92	CoverID  int    `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty,string"`
93	ArtistID int    `xml:"artistId,attr,omitempty" json:"artistId,omitempty,string"`
94	Artist   string `xml:"artist,attr,omitempty"   json:"artist,omitempty"`
95	// browsing by folder (getAlbumList)
96	Title    string `xml:"title,attr,omitempty"  json:"title,omitempty"`
97	Album    string `xml:"album,attr,omitempty"  json:"album,omitempty"`
98	ParentID int    `xml:"parent,attr,omitempty" json:"parent,omitempty,string"`
99	IsDir    bool   `xml:"isDir,attr,omitempty"  json:"isDir,omitempty"`
100	// browsing by tags (getAlbumList2)
101	Name       string        `xml:"name,attr,omitempty"    json:"name,omitempty"`
102	TrackCount int           `xml:"songCount,attr"         json:"songCount"`
103	Duration   int           `xml:"duration,attr"          json:"duration"`
104	Created    time.Time     `xml:"created,attr,omitempty" json:"created,omitempty"`
105	Tracks     []*TrackChild `xml:"song,omitempty"         json:"song,omitempty"`
106}
107
108type RandomTracks struct {
109	List []*TrackChild `xml:"song" json:"song"`
110}
111
112type TracksByGenre struct {
113	List []*TrackChild `xml:"song" json:"song"`
114}
115
116type TrackChild struct {
117	Album       string    `xml:"album,attr,omitempty"       json:"album,omitempty"`
118	AlbumID     int       `xml:"albumId,attr,omitempty"     json:"albumId,omitempty,string"`
119	Artist      string    `xml:"artist,attr,omitempty"      json:"artist,omitempty"`
120	ArtistID    int       `xml:"artistId,attr,omitempty"    json:"artistId,omitempty,string"`
121	Bitrate     int       `xml:"bitRate,attr,omitempty"     json:"bitRate,omitempty"`
122	ContentType string    `xml:"contentType,attr,omitempty" json:"contentType,omitempty"`
123	CoverID     int       `xml:"coverArt,attr,omitempty"    json:"coverArt,omitempty,string"`
124	CreatedAt   time.Time `xml:"created,attr,omitempty"     json:"created,omitempty"`
125	Duration    int       `xml:"duration,attr,omitempty"    json:"duration,omitempty"`
126	Genre       string    `xml:"genre,attr,omitempty"       json:"genre,omitempty"`
127	ID          int       `xml:"id,attr,omitempty"          json:"id,omitempty,string"`
128	IsDir       bool      `xml:"isDir,attr"                 json:"isDir"`
129	IsVideo     bool      `xml:"isVideo,attr"               json:"isVideo"`
130	ParentID    int       `xml:"parent,attr,omitempty"      json:"parent,omitempty,string"`
131	Path        string    `xml:"path,attr,omitempty"        json:"path,omitempty"`
132	Size        int       `xml:"size,attr,omitempty"        json:"size,omitempty"`
133	Suffix      string    `xml:"suffix,attr,omitempty"      json:"suffix,omitempty"`
134	Title       string    `xml:"title,attr"                 json:"title"`
135	TrackNumber int       `xml:"track,attr,omitempty"       json:"track,omitempty"`
136	DiscNumber  int       `xml:"discNumber,attr,omitempty"  json:"discNumber,omitempty"`
137	Type        string    `xml:"type,attr,omitempty"        json:"type,omitempty"`
138}
139
140type Artists struct {
141	IgnoredArticles string   `xml:"ignoredArticles,attr" json:"ignoredArticles"`
142	List            []*Index `xml:"index"                json:"index"`
143}
144
145type Artist struct {
146	ID         int      `xml:"id,attr,omitempty"       json:"id,string"`
147	Name       string   `xml:"name,attr"               json:"name"`
148	CoverID    int      `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty,string"`
149	AlbumCount int      `xml:"albumCount,attr"         json:"albumCount"`
150	Albums     []*Album `xml:"album,omitempty"         json:"album,omitempty"`
151}
152
153type Indexes struct {
154	LastModified    int      `xml:"lastModified,attr,omitempty" json:"lastModified"`
155	IgnoredArticles string   `xml:"ignoredArticles,attr"        json:"ignoredArticles"`
156	Index           []*Index `xml:"index"                       json:"index"`
157}
158
159type Index struct {
160	Name    string    `xml:"name,attr,omitempty" json:"name"`
161	Artists []*Artist `xml:"artist"              json:"artist"`
162}
163
164type Directory struct {
165	ID       int           `xml:"id,attr,omitempty"      json:"id,string"`
166	ParentID int           `xml:"parent,attr,omitempty"  json:"parent,omitempty,string"`
167	Name     string        `xml:"name,attr,omitempty"    json:"name"`
168	Starred  string        `xml:"starred,attr,omitempty" json:"starred,omitempty"`
169	Children []*TrackChild `xml:"child,omitempty"        json:"child,omitempty"`
170}
171
172type MusicFolders struct {
173	List []*MusicFolder `xml:"musicFolder" json:"musicFolder"`
174}
175
176type MusicFolder struct {
177	ID   int    `xml:"id,attr,omitempty"   json:"id,omitempty,string"`
178	Name string `xml:"name,attr,omitempty" json:"name,omitempty"`
179}
180
181type Licence struct {
182	Valid bool `xml:"valid,attr,omitempty" json:"valid,omitempty"`
183}
184
185type ScanStatus struct {
186	Scanning bool `xml:"scanning,attr"        json:"scanning"`
187	Count    int  `xml:"count,attr,omitempty" json:"count,omitempty"`
188}
189
190type SearchResultTwo struct {
191	Artists []*Directory  `xml:"artist,omitempty" json:"artist,omitempty"`
192	Albums  []*TrackChild `xml:"album,omitempty"  json:"album,omitempty"`
193	Tracks  []*TrackChild `xml:"song,omitempty"   json:"song,omitempty"`
194}
195
196type SearchResultThree struct {
197	Artists []*Artist     `xml:"artist,omitempty" json:"artist,omitempty"`
198	Albums  []*Album      `xml:"album,omitempty"  json:"album,omitempty"`
199	Tracks  []*TrackChild `xml:"song,omitempty"   json:"song,omitempty"`
200}
201
202type User struct {
203	Username            string `xml:"username,attr"            json:"username"`
204	ScrobblingEnabled   bool   `xml:"scrobblingEnabled,attr"   json:"scrobblingEnabled"`
205	AdminRole           bool   `xml:"adminRole,attr"           json:"adminRole"`
206	SettingsRole        bool   `xml:"settingsRole,attr"        json:"settingsRole"`
207	DownloadRole        bool   `xml:"downloadRole,attr"        json:"downloadRole"`
208	UploadRole          bool   `xml:"uploadRole,attr"          json:"uploadRole"`
209	PlaylistRole        bool   `xml:"playlistRole,attr"        json:"playlistRole"`
210	CoverArtRole        bool   `xml:"coverArtRole,attr"        json:"coverArtRole"`
211	CommentRole         bool   `xml:"commentRole,attr"         json:"commentRole"`
212	PodcastRole         bool   `xml:"podcastRole,attr"         json:"podcastRole"`
213	StreamRole          bool   `xml:"streamRole,attr"          json:"streamRole"`
214	JukeboxRole         bool   `xml:"jukeboxRole,attr"         json:"jukeboxRole"`
215	ShareRole           bool   `xml:"shareRole,attr"           json:"shareRole"`
216	VideoConversionRole bool   `xml:"videoConversionRole,attr" json:"videoConversionRole"`
217	Folder              []int  `xml:"folder,attr"              json:"folder"`
218}
219
220type Playlists struct {
221	List []*Playlist `xml:"playlist" json:"playlist"`
222}
223
224type Playlist struct {
225	ID        int           `xml:"id,attr"        json:"id"`
226	Name      string        `xml:"name,attr"      json:"name"`
227	Comment   string        `xml:"comment,attr"   json:"comment"`
228	Owner     string        `xml:"owner,attr"     json:"owner"`
229	SongCount int           `xml:"songCount,attr" json:"songCount"`
230	Created   time.Time     `xml:"created,attr"   json:"created"`
231	Duration  string        `xml:"duration,attr"  json:"duration,omitempty"`
232	Public    bool          `xml:"public,attr"    json:"public,omitempty"`
233	List      []*TrackChild `xml:"entry"          json:"entry"`
234}
235
236type SimilarArtist struct {
237	ID         int    `xml:"id,attr"                   json:"id,string"`
238	Name       string `xml:"name,attr"                 json:"name"`
239	AlbumCount int    `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"`
240}
241
242type ArtistInfo struct {
243	Biography      string           `xml:"biography"               json:"biography"`
244	MusicBrainzID  string           `xml:"musicBrainzId"           json:"musicBrainzId"`
245	LastFMURL      string           `xml:"lastFmUrl"               json:"lastFmUrl"`
246	SmallImageURL  string           `xml:"smallImageUrl"           json:"smallImageUrl"`
247	MediumImageURL string           `xml:"mediumImageUrl"          json:"mediumImageUrl"`
248	LargeImageURL  string           `xml:"largeImageUrl"           json:"largeImageUrl"`
249	SimilarArtist  []*SimilarArtist `xml:"similarArtist,omitempty" json:"similarArtist,omitempty"`
250}
251
252type Genres struct {
253	List []*Genre `xml:"genre" json:"genre"`
254}
255
256type Genre struct {
257	Name       string `xml:",chardata"                 json:"value"`
258	SongCount  int    `xml:"songCount,attr,omitempty"  json:"songCount,omitempty"`
259	AlbumCount int    `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"`
260}
261
262type PlayQueue struct {
263	Current   int           `xml:"current,attr,omitempty"  json:"current,omitempty"`
264	Position  int           `xml:"position,attr,omitempty" json:"position,omitempty"`
265	Username  string        `xml:"username,attr"           json:"username"`
266	Changed   time.Time     `xml:"changed,attr"            json:"changed"`
267	ChangedBy string        `xml:"changedBy,attr"          json:"changedBy"`
268	List      []*TrackChild `xml:"entry,omitempty"         json:"entry,omitempty"`
269}
270