mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Linking Album->Artist so that artist name shows on albumLists
This commit is contained in:
@@ -50,6 +50,9 @@ export type AlbumSummary = {
|
||||
name: string;
|
||||
year: string | undefined;
|
||||
genre: Genre | undefined;
|
||||
|
||||
artistName: string;
|
||||
artistId: string;
|
||||
};
|
||||
|
||||
export type Album = AlbumSummary & {};
|
||||
@@ -111,6 +114,8 @@ export const albumToAlbumSummary = (it: Album): AlbumSummary => ({
|
||||
name: it.name,
|
||||
year: it.year,
|
||||
genre: it.genre,
|
||||
artistName: it.artistName,
|
||||
artistId: it.artistId,
|
||||
});
|
||||
|
||||
export type StreamingHeader = "content-type" | "content-length" | "content-range" | "accept-ranges";
|
||||
|
||||
@@ -69,6 +69,8 @@ export type album = {
|
||||
_genre: string | undefined;
|
||||
_year: string | undefined;
|
||||
_coverArt: string | undefined;
|
||||
_artist: string;
|
||||
_artistId: string;
|
||||
};
|
||||
|
||||
export type artistSummary = {
|
||||
@@ -215,6 +217,8 @@ const asAlbum = (album: album) => ({
|
||||
name: album._name,
|
||||
year: album._year,
|
||||
genre: maybeAsGenre(album._genre),
|
||||
artistId: album._artistId,
|
||||
artistName: album._artist
|
||||
});
|
||||
|
||||
export const asGenre = (genreName: string) => ({
|
||||
@@ -361,6 +365,8 @@ export class Navidrome implements MusicService {
|
||||
name: album._name,
|
||||
year: album._year,
|
||||
genre: maybeAsGenre(album._genre),
|
||||
artistId: album._artistId,
|
||||
artistName: album._artist
|
||||
}));
|
||||
|
||||
getArtist = (
|
||||
@@ -379,6 +385,8 @@ export class Navidrome implements MusicService {
|
||||
name: album._name,
|
||||
year: album._year,
|
||||
genre: maybeAsGenre(album._genre),
|
||||
artistId: it._id,
|
||||
artistName: it._name,
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -422,6 +430,8 @@ export class Navidrome implements MusicService {
|
||||
name: album._name,
|
||||
year: album._year,
|
||||
genre: maybeAsGenre(album._genre),
|
||||
artistId: album._artistId,
|
||||
artistName: album._artist
|
||||
}));
|
||||
|
||||
search3 = (credentials: Credentials, q: any) =>
|
||||
|
||||
80
src/smapi.ts
80
src/smapi.ts
@@ -188,30 +188,15 @@ class SonosSoap {
|
||||
}
|
||||
}
|
||||
|
||||
export type ContainerType = "container" | "search" | "albumList";
|
||||
|
||||
export type Container = {
|
||||
itemType: "container" | "search";
|
||||
itemType: ContainerType;
|
||||
id: string;
|
||||
title: string;
|
||||
displayType: string | undefined
|
||||
};
|
||||
|
||||
const container = ({
|
||||
id,
|
||||
title,
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
}): Container => ({
|
||||
itemType: "container",
|
||||
id,
|
||||
title,
|
||||
});
|
||||
|
||||
const search = ({ id, title }: { id: string; title: string }): Container => ({
|
||||
itemType: "search",
|
||||
id,
|
||||
title,
|
||||
});
|
||||
|
||||
const genre = (genre: Genre) => ({
|
||||
itemType: "container",
|
||||
id: `genre:${genre.id}`,
|
||||
@@ -239,6 +224,8 @@ export const album = (
|
||||
) => ({
|
||||
itemType: "album",
|
||||
id: `album:${album.id}`,
|
||||
artist: album.artistName,
|
||||
artistId: album.artistId,
|
||||
title: album.name,
|
||||
albumArtURI: defaultAlbumArtURI(webAddress, accessToken, album),
|
||||
canPlay: true,
|
||||
@@ -262,10 +249,10 @@ export const track = (
|
||||
albumArtURI: defaultAlbumArtURI(webAddress, accessToken, track.album),
|
||||
artist: track.artist.name,
|
||||
artistId: track.artist.id,
|
||||
duration: `${track.duration}`,
|
||||
duration: track.duration,
|
||||
genre: track.album.genre?.name,
|
||||
genreId: track.album.genre?.id,
|
||||
trackNumber: `${track.number}`,
|
||||
trackNumber: track.number,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -490,23 +477,46 @@ function bindSmapiSoapServiceToExpress(
|
||||
case "root":
|
||||
return getMetadataResult({
|
||||
mediaCollection: [
|
||||
container({ id: "artists", title: "Artists" }),
|
||||
container({ id: "albums", title: "Albums" }),
|
||||
container({ id: "genres", title: "Genres" }),
|
||||
container({ id: "randomAlbums", title: "Random" }),
|
||||
container({ id: "starredAlbums", title: "Starred" }),
|
||||
container({
|
||||
{
|
||||
itemType: "container",
|
||||
id: "artists",
|
||||
title: "Artists",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "albums",
|
||||
title: "Albums",
|
||||
},
|
||||
{
|
||||
itemType: "container",
|
||||
id: "genres",
|
||||
title: "Genres",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "randomAlbums",
|
||||
title: "Random",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "starredAlbums",
|
||||
title: "Starred",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyAdded",
|
||||
title: "Recently Added",
|
||||
}),
|
||||
container({
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyPlayed",
|
||||
title: "Recently Played",
|
||||
}),
|
||||
container({
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "mostPlayed",
|
||||
title: "Most Played",
|
||||
}),
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
total: 8,
|
||||
@@ -514,9 +524,9 @@ function bindSmapiSoapServiceToExpress(
|
||||
case "search":
|
||||
return getMetadataResult({
|
||||
mediaCollection: [
|
||||
search({ id: "artists", title: "Artists" }),
|
||||
search({ id: "albums", title: "Albums" }),
|
||||
search({ id: "tracks", title: "Tracks" }),
|
||||
{ itemType: "search", id: "artists", title: "Artists" },
|
||||
{ itemType: "search", id: "albums", title: "Albums" },
|
||||
{ itemType: "search", id: "tracks", title: "Tracks" },
|
||||
],
|
||||
index: 0,
|
||||
total: 3,
|
||||
|
||||
@@ -7,7 +7,7 @@ import logger from "./logger";
|
||||
import { SOAP_PATH, STRINGS_ROUTE, PRESENTATION_MAP_ROUTE } from "./smapi";
|
||||
import qs from "querystring"
|
||||
|
||||
export const PRESENTATION_AND_STRINGS_VERSION = "12";
|
||||
export const PRESENTATION_AND_STRINGS_VERSION = "15";
|
||||
|
||||
export type Capability =
|
||||
| "search"
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Credentials } from "../src/smapi";
|
||||
|
||||
import { Service, Device } from "../src/sonos";
|
||||
import { Album, Artist, Track, albumToAlbumSummary, artistToArtistSummary } from "../src/music_service";
|
||||
import randomString from "../src/random_string";
|
||||
|
||||
const randomInt = (max: number) => Math.floor(Math.random() * Math.floor(max));
|
||||
const randomIpAddress = () => `127.0.${randomInt(255)}.${randomInt(255)}`;
|
||||
@@ -70,7 +71,7 @@ export function someCredentials(token: string): Credentials {
|
||||
|
||||
export function anArtist(fields: Partial<Artist> = {}): Artist {
|
||||
const id = uuid();
|
||||
return {
|
||||
const artist = {
|
||||
id,
|
||||
name: `Artist ${id}`,
|
||||
albums: [anAlbum(), anAlbum(), anAlbum()],
|
||||
@@ -85,6 +86,11 @@ export function anArtist(fields: Partial<Artist> = {}): Artist {
|
||||
],
|
||||
...fields,
|
||||
};
|
||||
artist.albums.forEach(album => {
|
||||
album.artistId = artist.id;
|
||||
album.artistName = artist.name;
|
||||
})
|
||||
return artist;
|
||||
}
|
||||
|
||||
export const HIP_HOP = { id: "genre_hip_hop", name: "Hip-Hop" };
|
||||
@@ -123,25 +129,33 @@ export function anAlbum(fields: Partial<Album> = {}): Album {
|
||||
name: `Album ${id}`,
|
||||
genre: randomGenre(),
|
||||
year: `19${randomInt(99)}`,
|
||||
artistId: `Artist ${uuid()}`,
|
||||
artistName: `Artist ${randomString()}`,
|
||||
...fields,
|
||||
};
|
||||
}
|
||||
|
||||
export const BLONDIE_ID = uuid();
|
||||
export const BLONDIE_NAME = "Blondie";
|
||||
export const BLONDIE: Artist = {
|
||||
id: uuid(),
|
||||
name: "Blondie",
|
||||
id: BLONDIE_ID,
|
||||
name: BLONDIE_NAME,
|
||||
albums: [
|
||||
{
|
||||
id: uuid(),
|
||||
name: "Blondie",
|
||||
year: "1976",
|
||||
genre: NEW_WAVE,
|
||||
artistId: BLONDIE_ID,
|
||||
artistName: BLONDIE_NAME
|
||||
},
|
||||
{
|
||||
id: uuid(),
|
||||
name: "Parallel Lines",
|
||||
year: "1978",
|
||||
genre: POP_ROCK,
|
||||
artistId: BLONDIE_ID,
|
||||
artistName: BLONDIE_NAME
|
||||
},
|
||||
],
|
||||
image: {
|
||||
@@ -152,13 +166,15 @@ export const BLONDIE: Artist = {
|
||||
similarArtists: [],
|
||||
};
|
||||
|
||||
export const BOB_MARLEY_ID = uuid();
|
||||
export const BOB_MARLEY_NAME = "Bob Marley";
|
||||
export const BOB_MARLEY: Artist = {
|
||||
id: uuid(),
|
||||
name: "Bob Marley",
|
||||
id: BOB_MARLEY_ID,
|
||||
name: BOB_MARLEY_NAME,
|
||||
albums: [
|
||||
{ id: uuid(), name: "Burin'", year: "1973", genre: REGGAE },
|
||||
{ id: uuid(), name: "Exodus", year: "1977", genre: REGGAE },
|
||||
{ id: uuid(), name: "Kaya", year: "1978", genre: SKA },
|
||||
{ id: uuid(), name: "Burin'", year: "1973", genre: REGGAE, artistId: BOB_MARLEY_ID, artistName: BOB_MARLEY_NAME },
|
||||
{ id: uuid(), name: "Exodus", year: "1977", genre: REGGAE, artistId: BOB_MARLEY_ID, artistName: BOB_MARLEY_NAME },
|
||||
{ id: uuid(), name: "Kaya", year: "1978", genre: SKA, artistId: BOB_MARLEY_ID, artistName: BOB_MARLEY_NAME },
|
||||
],
|
||||
image: {
|
||||
small: "http://localhost/BOB_MARLEY/sml",
|
||||
@@ -168,9 +184,11 @@ export const BOB_MARLEY: Artist = {
|
||||
similarArtists: [],
|
||||
};
|
||||
|
||||
export const MADONNA_ID = uuid();
|
||||
export const MADONNA_NAME = "Madonna";
|
||||
export const MADONNA: Artist = {
|
||||
id: uuid(),
|
||||
name: "Madonna",
|
||||
id: MADONNA_ID,
|
||||
name: MADONNA_NAME,
|
||||
albums: [],
|
||||
image: {
|
||||
small: "http://localhost/MADONNA/sml",
|
||||
@@ -180,21 +198,27 @@ export const MADONNA: Artist = {
|
||||
similarArtists: [],
|
||||
};
|
||||
|
||||
export const METALLICA_ID = uuid();
|
||||
export const METALLICA_NAME = "Metallica";
|
||||
export const METALLICA: Artist = {
|
||||
id: uuid(),
|
||||
name: "Metallica",
|
||||
id: METALLICA_ID,
|
||||
name: METALLICA_NAME,
|
||||
albums: [
|
||||
{
|
||||
id: uuid(),
|
||||
name: "Ride the Lightening",
|
||||
year: "1984",
|
||||
genre: METAL,
|
||||
artistId: METALLICA_ID,
|
||||
artistName: METALLICA_NAME,
|
||||
},
|
||||
{
|
||||
id: uuid(),
|
||||
name: "Master of Puppets",
|
||||
year: "1986",
|
||||
genre: METAL,
|
||||
artistId: METALLICA_ID,
|
||||
artistName: METALLICA_NAME,
|
||||
},
|
||||
],
|
||||
image: {
|
||||
|
||||
@@ -1374,26 +1374,24 @@ describe("Navidrome", () => {
|
||||
const tripHop = asGenre("Trip-Hop");
|
||||
|
||||
const album = anAlbum({ id: "album1", name: "Burnin", genre: hipHop });
|
||||
const albumSummary = albumToAlbumSummary(album);
|
||||
|
||||
const artist = anArtist({
|
||||
id: "artist1",
|
||||
name: "Bob Marley",
|
||||
albums: [album],
|
||||
});
|
||||
const artistSummary = artistToArtistSummary(artist);
|
||||
|
||||
const tracks = [
|
||||
aTrack({ artist: artistSummary, album: albumSummary, genre: hipHop }),
|
||||
aTrack({ artist: artistSummary, album: albumSummary, genre: hipHop }),
|
||||
aTrack({ artist: artistToArtistSummary(artist), album: albumToAlbumSummary(album), genre: hipHop }),
|
||||
aTrack({ artist: artistToArtistSummary(artist), album: albumToAlbumSummary(album), genre: hipHop }),
|
||||
aTrack({
|
||||
artist: artistSummary,
|
||||
album: albumSummary,
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album),
|
||||
genre: tripHop,
|
||||
}),
|
||||
aTrack({
|
||||
artist: artistSummary,
|
||||
album: albumSummary,
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album),
|
||||
genre: tripHop,
|
||||
}),
|
||||
];
|
||||
@@ -1433,19 +1431,17 @@ describe("Navidrome", () => {
|
||||
name: "Burnin",
|
||||
genre: flipFlop,
|
||||
});
|
||||
const albumSummary = albumToAlbumSummary(album);
|
||||
|
||||
const artist = anArtist({
|
||||
id: "artist1",
|
||||
name: "Bob Marley",
|
||||
albums: [album],
|
||||
});
|
||||
const artistSummary = artistToArtistSummary(artist);
|
||||
|
||||
const tracks = [
|
||||
aTrack({
|
||||
artist: artistSummary,
|
||||
album: albumSummary,
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album),
|
||||
genre: flipFlop,
|
||||
}),
|
||||
];
|
||||
@@ -1520,18 +1516,16 @@ describe("Navidrome", () => {
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album = anAlbum({ id: "album1", name: "Burnin", genre: pop });
|
||||
const albumSummary = albumToAlbumSummary(album);
|
||||
|
||||
const artist = anArtist({
|
||||
id: "artist1",
|
||||
name: "Bob Marley",
|
||||
albums: [album],
|
||||
});
|
||||
const artistSummary = artistToArtistSummary(artist);
|
||||
|
||||
const track = aTrack({
|
||||
artist: artistSummary,
|
||||
album: albumSummary,
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album),
|
||||
genre: pop,
|
||||
});
|
||||
|
||||
@@ -2730,11 +2724,11 @@ describe("Navidrome", () => {
|
||||
describe("searchAlbums", () => {
|
||||
describe("when there is 1 search results", () => {
|
||||
it("should return true", async () => {
|
||||
const artist = anArtist({ name: "#1" });
|
||||
const album = anAlbum({
|
||||
name: "foo woo",
|
||||
genre: { id: "pop", name: "pop" },
|
||||
});
|
||||
const artist = anArtist({ name: "#1", albums:[album] });
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
@@ -2765,17 +2759,17 @@ describe("Navidrome", () => {
|
||||
|
||||
describe("when there are many search results", () => {
|
||||
it("should return true", async () => {
|
||||
const artist1 = anArtist({ name: "artist1" });
|
||||
const album1 = anAlbum({
|
||||
name: "album1",
|
||||
genre: { id: "pop", name: "pop" },
|
||||
});
|
||||
const artist1 = anArtist({ name: "artist1", albums: [album1] });
|
||||
|
||||
const artist2 = anArtist({ name: "artist2" });
|
||||
const album2 = anAlbum({
|
||||
name: "album2",
|
||||
genre: { id: "pop", name: "pop" },
|
||||
});
|
||||
const artist2 = anArtist({ name: "artist2", albums: [album2] });
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
|
||||
@@ -241,6 +241,8 @@ describe("album", () => {
|
||||
title: someAlbum.name,
|
||||
albumArtURI: defaultAlbumArtURI(webAddress, accessToken, someAlbum),
|
||||
canPlay: true,
|
||||
artist: someAlbum.artistName,
|
||||
artistId: someAlbum.artistId
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -633,7 +635,7 @@ describe("api", () => {
|
||||
musicLibrary.searchTracks.mockResolvedValue([track1, track2]);
|
||||
});
|
||||
|
||||
it.only("should return the tracks", async () => {
|
||||
it("should return the tracks", async () => {
|
||||
const term = "whoopie";
|
||||
|
||||
const result = await ws.searchAsync({
|
||||
@@ -642,7 +644,15 @@ describe("api", () => {
|
||||
});
|
||||
expect(result[0]).toEqual(
|
||||
searchResult({
|
||||
mediaCollection: tracks.map((it) => track(rootUrl, accessToken, it)),
|
||||
mediaCollection: tracks.map((it) => {
|
||||
const t = track(rootUrl, accessToken, it) as any;
|
||||
t.trackMetadata = {
|
||||
...t.trackMetadata,
|
||||
duration: `${t.trackMetadata.duration}`,
|
||||
trackNumber: `${t.trackMetadata.trackNumber}`,
|
||||
}
|
||||
return t;
|
||||
}),
|
||||
index: 0,
|
||||
total: 2,
|
||||
})
|
||||
@@ -722,30 +732,30 @@ describe("api", () => {
|
||||
getMetadataResult({
|
||||
mediaCollection: [
|
||||
{ itemType: "container", id: "artists", title: "Artists" },
|
||||
{ itemType: "container", id: "albums", title: "Albums" },
|
||||
{ itemType: "albumList", id: "albums", title: "Albums" },
|
||||
{ itemType: "container", id: "genres", title: "Genres" },
|
||||
{
|
||||
itemType: "container",
|
||||
itemType: "albumList",
|
||||
id: "randomAlbums",
|
||||
title: "Random",
|
||||
},
|
||||
{
|
||||
itemType: "container",
|
||||
itemType: "albumList",
|
||||
id: "starredAlbums",
|
||||
title: "Starred",
|
||||
},
|
||||
{
|
||||
itemType: "container",
|
||||
itemType: "albumList",
|
||||
id: "recentlyAdded",
|
||||
title: "Recently Added",
|
||||
},
|
||||
{
|
||||
itemType: "container",
|
||||
itemType: "albumList",
|
||||
id: "recentlyPlayed",
|
||||
title: "Recently Played",
|
||||
},
|
||||
{
|
||||
itemType: "container",
|
||||
itemType: "albumList",
|
||||
id: "mostPlayed",
|
||||
title: "Most Played",
|
||||
},
|
||||
@@ -853,6 +863,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: artistWithManyAlbums.albums.length,
|
||||
@@ -884,6 +896,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 2,
|
||||
total: artistWithManyAlbums.albums.length,
|
||||
@@ -1137,6 +1151,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1180,6 +1196,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1223,6 +1241,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1266,6 +1286,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1309,6 +1331,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1350,6 +1374,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 6,
|
||||
@@ -1391,6 +1417,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 2,
|
||||
total: 6,
|
||||
@@ -1430,6 +1458,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 4,
|
||||
@@ -1472,6 +1502,8 @@ describe("api", () => {
|
||||
title: it.name,
|
||||
albumArtURI: defaultAlbumArtURI(rootUrl, accessToken, it),
|
||||
canPlay: true,
|
||||
artistId: it.artistId,
|
||||
artist: it.artistName
|
||||
})),
|
||||
index: 0,
|
||||
total: 4,
|
||||
|
||||
Reference in New Issue
Block a user