feat(subsonic): add support for multi-valued album artist tags

closes #103

a

a

a

r

a

a

a

a

a

a

a

a

a

a
This commit is contained in:
sentriz
2023-07-31 23:07:41 +01:00
parent 908c7cf088
commit 3ac77823c3
27 changed files with 641 additions and 266 deletions

View File

@@ -62,9 +62,8 @@ func (c *Controller) ServeHome(r *http.Request) *Response {
// recent folders box
c.DB.
Where("tag_artist_id IS NOT NULL").
Order("created_at DESC").
Limit(8).
Limit(20).
Find(&data.RecentFolders)
data.IsScanning = c.Scanner.IsScanning()
if tStr, err := c.DB.GetSetting("last_scan_time"); err != nil {

View File

@@ -90,7 +90,7 @@ func (c *Controller) ServeGetMusicDirectory(r *http.Request) *spec.Response {
c.DB.
Where("album_id=?", id.Value).
Preload("Album").
Preload("Album.TagArtist").
Preload("Album.Artists").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Order("filename").
@@ -178,7 +178,7 @@ func (c *Controller) ServeGetAlbumList(r *http.Request) *spec.Response {
Select("albums.*, count(tracks.id) child_count, sum(tracks.length) duration").
Joins("LEFT JOIN tracks ON tracks.album_id=albums.id").
Group("albums.id").
Where("albums.tag_artist_id IS NOT NULL").
Joins("JOIN album_artists ON album_artists.album_id=albums.id").
Offset(params.GetOrInt("offset", 0)).
Limit(params.GetOrInt("size", 10)).
Preload("Parent").
@@ -236,7 +236,7 @@ func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response {
// search "albums"
var albums []*db.Album
q = c.DB.Where(`tag_artist_id IS NOT NULL`)
q = c.DB.Joins("JOIN album_artists ON album_artists.album_id=albums.id")
for _, s := range queries {
q = q.Where(`right_path LIKE ? OR right_path_u_dec LIKE ?`, s, s)
}
@@ -323,7 +323,7 @@ func (c *Controller) ServeGetStarred(r *http.Request) *spec.Response {
// "albums"
var albums []*db.Album
q = c.DB.
Where("tag_artist_id IS NOT NULL").
Joins("JOIN album_artists ON album_artists.album_id=albums.id").
Joins("JOIN album_stars ON albums.id=album_stars.album_id").
Where("album_stars.user_id=?", user.ID).
Preload("AlbumStar", "user_id=?", user.ID).

View File

@@ -24,7 +24,8 @@ func (c *Controller) ServeGetArtists(r *http.Request) *spec.Response {
var artists []*db.Artist
q := c.DB.
Select("*, count(sub.id) album_count").
Joins("LEFT JOIN albums sub ON artists.id=sub.tag_artist_id").
Joins("JOIN album_artists ON album_artists.artist_id=artists.id").
Joins("JOIN albums sub ON sub.id=album_artists.album_id").
Preload("ArtistStar", "user_id=?", user.ID).
Preload("ArtistRating", "user_id=?", user.ID).
Group("artists.id").
@@ -69,11 +70,10 @@ func (c *Controller) ServeGetArtist(r *http.Request) *spec.Response {
return db.
Select("*, count(sub.id) child_count, sum(sub.length) duration").
Joins("LEFT JOIN tracks sub ON albums.id=sub.album_id").
Preload("AlbumStar", "user_id=?", user.ID).
Preload("AlbumRating", "user_id=?", user.ID).
Order("albums.right_path").
Group("albums.id")
}).
Preload("Albums.Artists").
Preload("ArtistStar", "user_id=?", user.ID).
Preload("ArtistRating", "user_id=?", user.ID).
First(artist, id.Value)
@@ -81,7 +81,7 @@ func (c *Controller) ServeGetArtist(r *http.Request) *spec.Response {
sub.Artist = spec.NewArtistByTags(artist)
sub.Artist.Albums = make([]*spec.Album, len(artist.Albums))
for i, album := range artist.Albums {
sub.Artist.Albums[i] = spec.NewAlbumByTags(album, artist)
sub.Artist.Albums[i] = spec.NewAlbumByTags(album, album.Artists)
}
sub.Artist.AlbumCount = len(artist.Albums)
return sub
@@ -98,7 +98,7 @@ func (c *Controller) ServeGetAlbum(r *http.Request) *spec.Response {
err = c.DB.
Select("albums.*, count(tracks.id) child_count, sum(tracks.length) duration").
Joins("LEFT JOIN tracks ON tracks.album_id=albums.id").
Preload("TagArtist").
Preload("Artists").
Preload("Genres").
Preload("Tracks", func(db *gorm.DB) *gorm.DB {
return db.
@@ -114,7 +114,7 @@ func (c *Controller) ServeGetAlbum(r *http.Request) *spec.Response {
return spec.NewError(10, "couldn't find an album with that id")
}
sub := spec.NewResponse()
sub.Album = spec.NewAlbumByTags(album, album.TagArtist)
sub.Album = spec.NewAlbumByTags(album, album.Artists)
sub.Album.Tracks = make([]*spec.TrackChild, len(album.Tracks))
transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))
@@ -140,7 +140,7 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response {
q := c.DB.DB
switch listType {
case "alphabeticalByArtist":
q = q.Joins("JOIN artists ON albums.tag_artist_id=artists.id")
q = q.Joins("JOIN artists ON artists.id=album_artists.artist_id")
q = q.Order("artists.name")
case "alphabeticalByName":
q = q.Order("tag_title")
@@ -186,10 +186,10 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response {
Select("albums.*, count(tracks.id) child_count, sum(tracks.length) duration").
Joins("LEFT JOIN tracks ON tracks.album_id=albums.id").
Group("albums.id").
Where("albums.tag_artist_id IS NOT NULL").
Joins("JOIN album_artists ON album_artists.album_id=albums.id").
Offset(params.GetOrInt("offset", 0)).
Limit(params.GetOrInt("size", 10)).
Preload("TagArtist").
Preload("Artists").
Preload("AlbumStar", "user_id=?", user.ID).
Preload("AlbumRating", "user_id=?", user.ID).
Find(&albums)
@@ -198,7 +198,7 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response {
List: make([]*spec.Album, len(albums)),
}
for i, album := range albums {
sub.AlbumsTwo.List[i] = spec.NewAlbumByTags(album, album.TagArtist)
sub.AlbumsTwo.List[i] = spec.NewAlbumByTags(album, album.Artists)
}
return sub
}
@@ -225,7 +225,9 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response {
for _, s := range queries {
q = q.Where(`name LIKE ? OR name_u_dec LIKE ?`, s, s)
}
q = q.Joins("JOIN albums ON albums.tag_artist_id=artists.id").
q = q.
Joins("JOIN album_artists ON album_artists.artist_id=artists.id").
Joins("JOIN albums ON albums.id=album_artists.album_id").
Preload("ArtistStar", "user_id=?", user.ID).
Preload("ArtistRating", "user_id=?", user.ID).
Offset(params.GetOrInt("artistOffset", 0)).
@@ -243,14 +245,15 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response {
// search albums
var albums []*db.Album
q = c.DB.
Preload("TagArtist").
Preload("Artists").
Preload("Genres").
Preload("AlbumStar", "user_id=?", user.ID).
Preload("AlbumRating", "user_id=?", user.ID)
for _, s := range queries {
q = q.Where(`tag_title LIKE ? OR tag_title_u_dec LIKE ?`, s, s)
}
q = q.Offset(params.GetOrInt("albumOffset", 0)).
q = q.
Offset(params.GetOrInt("albumOffset", 0)).
Limit(params.GetOrInt("albumCount", 20))
if m := getMusicFolder(c.MusicPaths, params); m != "" {
q = q.Where("root_dir=?", m)
@@ -259,19 +262,19 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response {
return spec.NewError(0, "find albums: %v", err)
}
for _, a := range albums {
results.Albums = append(results.Albums, spec.NewAlbumByTags(a, a.TagArtist))
results.Albums = append(results.Albums, spec.NewAlbumByTags(a, a.Artists))
}
// search tracks
var tracks []*db.Track
q = c.DB.
Preload("Album").
Preload("Album.TagArtist").
Preload("Album.Artists").
Preload("Genres").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID)
for _, s := range queries {
q = q.Where(`tag_title LIKE ? OR tag_title_u_dec LIKE ?`, s, s)
q = q.Where(`tracks.tag_title LIKE ? OR tracks.tag_title_u_dec LIKE ?`, s, s)
}
q = q.Offset(params.GetOrInt("songOffset", 0)).
Limit(params.GetOrInt("songCount", 20))
@@ -369,7 +372,8 @@ func (c *Controller) ServeGetArtistInfoTwo(r *http.Request) *spec.Response {
err = c.DB.
Select("artists.*, count(albums.id) album_count").
Where("name=?", similarInfo.Name).
Joins("LEFT JOIN albums ON artists.id=albums.tag_artist_id").
Joins("LEFT JOIN album_artists ON album_artists.artist_id=artists.id").
Joins("LEFT JOIN albums ON albums.id=album_artists.album_id").
Group("artists.id").
Find(&artist).
Error
@@ -421,7 +425,7 @@ func (c *Controller) ServeGetSongsByGenre(r *http.Request) *spec.Response {
Joins("JOIN track_genres ON track_genres.track_id=tracks.id").
Joins("JOIN genres ON track_genres.genre_id=genres.id AND genres.name=?", genre).
Preload("Album").
Preload("Album.TagArtist").
Preload("Album.Artists").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Offset(params.GetOrInt("offset", 0)).
@@ -429,6 +433,7 @@ func (c *Controller) ServeGetSongsByGenre(r *http.Request) *spec.Response {
if m := getMusicFolder(c.MusicPaths, params); m != "" {
q = q.Where("albums.root_dir=?", m)
}
q = q.Group("tracks.id")
if err := q.Find(&tracks).Error; err != nil {
return spec.NewError(0, "error finding tracks: %v", err)
}
@@ -457,11 +462,13 @@ func (c *Controller) ServeGetStarredTwo(r *http.Request) *spec.Response {
// artists
var artists []*db.Artist
q := c.DB.
Group("artists.id").
Joins("JOIN artist_stars ON artist_stars.artist_id=artists.id").
Where("artist_stars.user_id=?", user.ID).
Joins("JOIN album_artists ON album_artists.artist_id=artists.id").
Joins("JOIN albums ON albums.id=album_artists.album_id").
Preload("ArtistStar", "user_id=?", user.ID).
Preload("ArtistRating", "user_id=?", user.ID)
Preload("ArtistRating", "user_id=?", user.ID).
Group("artists.id")
if m := getMusicFolder(c.MusicPaths, params); m != "" {
q = q.Where("albums.root_dir=?", m)
}
@@ -477,7 +484,7 @@ func (c *Controller) ServeGetStarredTwo(r *http.Request) *spec.Response {
q = c.DB.
Joins("JOIN album_stars ON album_stars.album_id=albums.id").
Where("album_stars.user_id=?", user.ID).
Preload("TagArtist").
Preload("Artists").
Preload("AlbumStar", "user_id=?", user.ID).
Preload("AlbumRating", "user_id=?", user.ID)
if m := getMusicFolder(c.MusicPaths, params); m != "" {
@@ -487,7 +494,7 @@ func (c *Controller) ServeGetStarredTwo(r *http.Request) *spec.Response {
return spec.NewError(0, "find albums: %v", err)
}
for _, a := range albums {
results.Albums = append(results.Albums, spec.NewAlbumByTags(a, a.TagArtist))
results.Albums = append(results.Albums, spec.NewAlbumByTags(a, a.Artists))
}
// tracks
@@ -572,10 +579,13 @@ func (c *Controller) ServeGetTopSongs(r *http.Request) *spec.Response {
var tracks []*db.Track
err = c.DB.
Preload("Album").
Where("artist_id=? AND tracks.tag_title IN (?)", artist.ID, topTrackNames).
Joins("JOIN albums ON albums.id=tracks.album_id").
Joins("JOIN album_artists ON album_artists.album_id=albums.id").
Where("album_artists.artist_id=? AND tracks.tag_title IN (?)", artist.ID, topTrackNames).
Limit(count).
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Group("tracks.id").
Find(&tracks).
Error
if err != nil {
@@ -611,7 +621,6 @@ func (c *Controller) ServeGetSimilarSongs(r *http.Request) *spec.Response {
var track db.Track
err = c.DB.
Preload("Artist").
Preload("Album").
Where("id=?", id.Value).
First(&track).
@@ -620,7 +629,7 @@ func (c *Controller) ServeGetSimilarSongs(r *http.Request) *spec.Response {
return spec.NewError(10, "couldn't find a track with that id")
}
similarTracks, err := c.LastFMClient.TrackGetSimilarTracks(apiKey, track.Artist.Name, track.TagTitle)
similarTracks, err := c.LastFMClient.TrackGetSimilarTracks(apiKey, track.TagTrackArtist, track.TagTitle)
if err != nil {
return spec.NewError(0, "fetching track similar tracks: %v", err)
}
@@ -635,11 +644,10 @@ func (c *Controller) ServeGetSimilarSongs(r *http.Request) *spec.Response {
var tracks []*db.Track
err = c.DB.
Preload("Artist").
Select("tracks.*").
Preload("Album").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Select("tracks.*").
Where("tracks.tag_title IN (?)", similarTrackNames).
Order(gorm.Expr("random()")).
Limit(count).
@@ -708,9 +716,11 @@ func (c *Controller) ServeGetSimilarSongsTwo(r *http.Request) *spec.Response {
Preload("Album").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Joins("JOIN artists on tracks.artist_id=artists.id").
Joins("JOIN album_artists ON album_artists.album_id=tracks.album_id").
Joins("JOIN artists ON artists.id=album_artists.artist_id").
Where("artists.name IN (?)", artistNames).
Order(gorm.Expr("random()")).
Group("tracks.id").
Limit(count).
Find(&tracks).
Error

View File

@@ -62,7 +62,7 @@ func (c *Controller) ServeScrobble(r *http.Request) *spec.Response {
}
track := &db.Track{}
if err := c.DB.Preload("Album").Preload("Artist").First(track, id.Value).Error; err != nil {
if err := c.DB.Preload("Album").Preload("Album.Artists").First(track, id.Value).Error; err != nil {
return spec.NewError(0, "error finding track: %v", err)
}
@@ -236,7 +236,7 @@ func (c *Controller) ServeGetSong(r *http.Request) *spec.Response {
err = c.DB.
Where("id=?", id.Value).
Preload("Album").
Preload("Album.TagArtist").
Preload("Album.Artists").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
First(&track).
@@ -256,7 +256,7 @@ func (c *Controller) ServeGetRandomSongs(r *http.Request) *spec.Response {
q := c.DB.DB.
Limit(params.GetOrInt("size", 10)).
Preload("Album").
Preload("Album.TagArtist").
Preload("Album.Artists").
Preload("TrackStar", "user_id=?", user.ID).
Preload("TrackRating", "user_id=?", user.ID).
Joins("JOIN albums ON tracks.album_id=albums.id").

View File

@@ -217,7 +217,7 @@ func playlistRender(c *Controller, params params.Params, playlistID string, play
switch id := file.SID(); id.Type {
case specid.Track:
var track db.Track
if err := c.DB.Where("id=?", id.Value).Preload("Album").Preload("Album.TagArtist").Preload("TrackStar", "user_id=?", user.ID).Preload("TrackRating", "user_id=?", user.ID).Find(&track).Error; errors.Is(err, gorm.ErrRecordNotFound) {
if err := c.DB.Where("id=?", id.Value).Preload("Album").Preload("Album.Artists").Preload("TrackStar", "user_id=?", user.ID).Preload("TrackRating", "user_id=?", user.ID).Find(&track).Error; errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("load track by id: %w", err)
}
trch = spec.NewTCTrackByFolder(&track, track.Album)

View File

@@ -150,8 +150,9 @@ func coverGetPathArtist(dbc *db.DB, id int) (string, error) {
folder := &db.Album{}
err := dbc.DB.
Select("parent.id, parent.root_dir, parent.left_path, parent.right_path, parent.cover").
Joins("JOIN album_artists ON album_artists.album_id").
Where("album_artists.artist_id=?", id).
Joins("JOIN albums parent ON parent.id=albums.parent_id").
Where("albums.tag_artist_id=?", id).
Find(folder).
Error
if err != nil {

View File

@@ -2,12 +2,13 @@ package spec
import (
"path"
"sort"
"strings"
"go.senan.xyz/gonic/db"
)
func NewAlbumByTags(a *db.Album, artist *db.Artist) *Album {
func NewAlbumByTags(a *db.Album, artists []*db.Artist) *Album {
ret := &Album{
Created: a.CreatedAt,
ID: a.SID(),
@@ -27,9 +28,16 @@ func NewAlbumByTags(a *db.Album, artist *db.Artist) *Album {
if a.AlbumRating != nil {
ret.UserRating = a.AlbumRating.Rating
}
if artist != nil {
ret.Artist = artist.Name
ret.ArtistID = artist.SID()
sort.Slice(artists, func(i, j int) bool {
return artists[i].ID < artists[j].ID
})
if len(artists) > 0 {
ret.Artist = artists[0].Name
ret.ArtistID = artists[0].SID()
}
for _, a := range artists {
ret.Artists = append(ret.Artists, a.Name)
ret.ArtistIDs = append(ret.ArtistIDs, a.SID())
}
return ret
}
@@ -69,8 +77,11 @@ func NewTrackByTags(t *db.Track, album *db.Album) *TrackChild {
if t.TrackRating != nil {
ret.UserRating = t.TrackRating.Rating
}
if album.TagArtist != nil {
ret.ArtistID = album.TagArtist.SID()
if len(album.Artists) > 0 {
sort.Slice(album.Artists, func(i, j int) bool {
return album.Artists[i].ID < album.Artists[j].ID
})
ret.ArtistID = album.Artists[0].SID()
}
// replace tags that we're present
if ret.Title == "" {

View File

@@ -113,11 +113,13 @@ type Albums struct {
type Album struct {
// common
ID *specid.ID `xml:"id,attr,omitempty" json:"id"`
CoverID *specid.ID `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
ArtistID *specid.ID `xml:"artistId,attr,omitempty" json:"artistId,omitempty"`
Artist string `xml:"artist,attr,omitempty" json:"artist,omitempty"`
Created time.Time `xml:"created,attr,omitempty" json:"created,omitempty"`
ID *specid.ID `xml:"id,attr,omitempty" json:"id"`
CoverID *specid.ID `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
ArtistID *specid.ID `xml:"artistId,attr,omitempty" json:"artistId,omitempty"`
Artist string `xml:"artist,attr,omitempty" json:"artist,omitempty"`
ArtistIDs []*specid.ID `xml:"artistIds,attr,omitempty" json:"artistIds,omitempty"`
Artists []string `xml:"artists,attr,omitempty" json:"artists,omitempty"`
Created time.Time `xml:"created,attr,omitempty" json:"created,omitempty"`
// browsing by folder (eg. getAlbumList)
Title string `xml:"title,attr,omitempty" json:"title"`
Album string `xml:"album,attr,omitempty" json:"album"`

View File

@@ -6,32 +6,6 @@
"serverVersion": "",
"albumList": {
"album": [
{
"id": "al-13",
"coverArt": "al-13",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-2",
"album": "",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-12",
"coverArt": "al-12",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-1",
"album": "",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-7",
"coverArt": "al-7",
@@ -45,6 +19,58 @@
"songCount": 3,
"duration": 300
},
{
"id": "al-4",
"coverArt": "al-4",
"artist": "artist-0",
"created": "2019-11-30T00:00:00Z",
"title": "album-1",
"album": "",
"parent": "al-2",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-3",
"coverArt": "al-3",
"artist": "artist-0",
"created": "2019-11-30T00:00:00Z",
"title": "album-0",
"album": "",
"parent": "al-2",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-11",
"coverArt": "al-11",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-0",
"album": "",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-13",
"coverArt": "al-13",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-2",
"album": "",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-5",
"coverArt": "al-5",
@@ -71,32 +97,6 @@
"songCount": 3,
"duration": 300
},
{
"id": "al-11",
"coverArt": "al-11",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-0",
"album": "",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-3",
"coverArt": "al-3",
"artist": "artist-0",
"created": "2019-11-30T00:00:00Z",
"title": "album-0",
"album": "",
"parent": "al-2",
"isDir": true,
"name": "",
"songCount": 3,
"duration": 300
},
{
"id": "al-8",
"coverArt": "al-8",
@@ -111,13 +111,13 @@
"duration": 300
},
{
"id": "al-4",
"coverArt": "al-4",
"artist": "artist-0",
"id": "al-12",
"coverArt": "al-12",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "album-1",
"album": "",
"parent": "al-2",
"parent": "al-10",
"isDir": true,
"name": "",
"songCount": 3,

View File

@@ -11,6 +11,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -24,6 +26,8 @@
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -37,6 +41,8 @@
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -50,6 +56,8 @@
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -63,6 +71,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -76,6 +86,8 @@
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -89,6 +101,8 @@
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -102,6 +116,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -115,6 +131,8 @@
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -11,6 +11,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -24,6 +26,8 @@
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -37,6 +41,8 @@
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -50,6 +56,8 @@
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -63,6 +71,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -76,6 +86,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -89,6 +101,8 @@
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -102,6 +116,8 @@
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -115,6 +131,8 @@
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -11,6 +11,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -24,6 +26,8 @@
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -37,6 +41,8 @@
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -50,6 +56,8 @@
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -63,6 +71,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -76,6 +86,8 @@
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -89,6 +101,8 @@
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -102,6 +116,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -115,6 +131,8 @@
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -6,24 +6,13 @@
"serverVersion": "",
"albumList2": {
"album": [
{
"id": "al-13",
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-2",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-4",
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -33,49 +22,12 @@
"year": 2021
},
{
"id": "al-11",
"coverArt": "al-11",
"id": "al-13",
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-3",
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-7",
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-5",
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -84,11 +36,43 @@
"duration": 300,
"year": 2021
},
{
"id": "al-3",
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-11",
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-9",
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -102,6 +86,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -115,6 +101,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -122,6 +110,36 @@
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-5",
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-2",
"songCount": 3,
"duration": 300,
"year": 2021
},
{
"id": "al-7",
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
"name": "album-0",
"songCount": 3,
"duration": 300,
"year": 2021
}
]
}

View File

@@ -9,6 +9,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -14,6 +14,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -27,6 +29,8 @@
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -40,6 +44,8 @@
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -14,6 +14,8 @@
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -27,6 +29,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -40,6 +44,8 @@
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -14,6 +14,8 @@
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -27,6 +29,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -40,6 +44,8 @@
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",

View File

@@ -11,6 +11,8 @@
"coverArt": "al-3",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -25,6 +27,8 @@
"coverArt": "al-4",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -39,6 +43,8 @@
"coverArt": "al-5",
"artistId": "ar-1",
"artist": "artist-0",
"artistIds": ["ar-1"],
"artists": ["artist-0"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -53,6 +59,8 @@
"coverArt": "al-7",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -67,6 +75,8 @@
"coverArt": "al-8",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -81,6 +91,8 @@
"coverArt": "al-9",
"artistId": "ar-2",
"artist": "artist-1",
"artistIds": ["ar-2"],
"artists": ["artist-1"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -95,6 +107,8 @@
"coverArt": "al-11",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -109,6 +123,8 @@
"coverArt": "al-12",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",
@@ -123,6 +139,8 @@
"coverArt": "al-13",
"artistId": "ar-3",
"artist": "artist-2",
"artistIds": ["ar-3"],
"artists": ["artist-2"],
"created": "2019-11-30T00:00:00Z",
"title": "",
"album": "",