mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Add similar artists to Artist
This commit is contained in:
@@ -42,6 +42,7 @@ export const NO_IMAGES: Images = {
|
|||||||
export type Artist = ArtistSummary & {
|
export type Artist = ArtistSummary & {
|
||||||
image: Images
|
image: Images
|
||||||
albums: AlbumSummary[];
|
albums: AlbumSummary[];
|
||||||
|
similarArtists: ArtistSummary[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AlbumSummary = {
|
export type AlbumSummary = {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import sharp from "sharp";
|
|||||||
import axios, { AxiosRequestConfig } from "axios";
|
import axios, { AxiosRequestConfig } from "axios";
|
||||||
import { Encryption } from "./encryption";
|
import { Encryption } from "./encryption";
|
||||||
import randomString from "./random_string";
|
import randomString from "./random_string";
|
||||||
|
import { fold } from "fp-ts/lib/Option";
|
||||||
|
|
||||||
export const BROWSER_HEADERS = {
|
export const BROWSER_HEADERS = {
|
||||||
accept:
|
accept:
|
||||||
@@ -117,10 +118,12 @@ export type artistInfo = {
|
|||||||
smallImageUrl: string | undefined;
|
smallImageUrl: string | undefined;
|
||||||
mediumImageUrl: string | undefined;
|
mediumImageUrl: string | undefined;
|
||||||
largeImageUrl: string | undefined;
|
largeImageUrl: string | undefined;
|
||||||
|
similarArtist: artistSummary[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ArtistInfo = {
|
export type ArtistInfo = {
|
||||||
image: Images;
|
image: Images;
|
||||||
|
similarArtist: {id:string, name:string}[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GetArtistInfoResponse = SubsonicResponse & {
|
export type GetArtistInfoResponse = SubsonicResponse & {
|
||||||
@@ -255,6 +258,7 @@ export class Navidrome implements MusicService {
|
|||||||
"subsonic-response.albumList.album",
|
"subsonic-response.albumList.album",
|
||||||
"subsonic-response.album.song",
|
"subsonic-response.album.song",
|
||||||
"subsonic-response.genres.genre",
|
"subsonic-response.genres.genre",
|
||||||
|
"subsonic-response.artistInfo.similarArtist"
|
||||||
],
|
],
|
||||||
}).xml2js(response.data) as SubconicEnvelope
|
}).xml2js(response.data) as SubconicEnvelope
|
||||||
)
|
)
|
||||||
@@ -301,6 +305,7 @@ export class Navidrome implements MusicService {
|
|||||||
medium: validate(it.artistInfo.mediumImageUrl),
|
medium: validate(it.artistInfo.mediumImageUrl),
|
||||||
large: validate(it.artistInfo.largeImageUrl),
|
large: validate(it.artistInfo.largeImageUrl),
|
||||||
},
|
},
|
||||||
|
similarArtist: (it.artistInfo.similarArtist || []).map(artist => ({id: artist._id, name: artist._name}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
getAlbum = (credentials: Credentials, id: string): Promise<Album> =>
|
getAlbum = (credentials: Credentials, id: string): Promise<Album> =>
|
||||||
@@ -341,6 +346,7 @@ export class Navidrome implements MusicService {
|
|||||||
name: artist.name,
|
name: artist.name,
|
||||||
image: artistInfo.image,
|
image: artistInfo.image,
|
||||||
albums: artist.albums,
|
albums: artist.albums,
|
||||||
|
similarArtists: artistInfo.similarArtist
|
||||||
}));
|
}));
|
||||||
|
|
||||||
getCoverArt = (credentials: Credentials, id: string, size?: number) =>
|
getCoverArt = (credentials: Credentials, id: string, size?: number) =>
|
||||||
@@ -372,16 +378,15 @@ export class Navidrome implements MusicService {
|
|||||||
albums: (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
albums: (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
||||||
navidrome
|
navidrome
|
||||||
.getJSON<GetAlbumListResponse>(credentials, "/rest/getAlbumList", {
|
.getJSON<GetAlbumListResponse>(credentials, "/rest/getAlbumList", {
|
||||||
...pipe(
|
...fold(
|
||||||
O.fromNullable(q.genre),
|
() => ({
|
||||||
O.map<string, getAlbumListParams>((genre) => ({
|
type: "alphabeticalByArtist",
|
||||||
|
}),
|
||||||
|
(genre) => ({
|
||||||
type: "byGenre",
|
type: "byGenre",
|
||||||
genre,
|
genre,
|
||||||
})),
|
})
|
||||||
O.getOrElse<getAlbumListParams>(() => ({
|
)(O.fromNullable(q.genre)),
|
||||||
type: "alphabeticalByArtist",
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
size: MAX_ALBUM_LIST,
|
size: MAX_ALBUM_LIST,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ export function anArtist(fields: Partial<Artist> = {}): Artist {
|
|||||||
medium: `/artist/art/${id}/small`,
|
medium: `/artist/art/${id}/small`,
|
||||||
large: `/artist/art/${id}/large`,
|
large: `/artist/art/${id}/large`,
|
||||||
},
|
},
|
||||||
|
similarArtists: [
|
||||||
|
{ id: uuid(), name: "Similar artist1"},
|
||||||
|
{ id: uuid(), name: "Similar artist2"},
|
||||||
|
],
|
||||||
...fields,
|
...fields,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -134,6 +138,7 @@ export const BLONDIE: Artist = {
|
|||||||
medium: undefined,
|
medium: undefined,
|
||||||
large: undefined,
|
large: undefined,
|
||||||
},
|
},
|
||||||
|
similarArtists: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BOB_MARLEY: Artist = {
|
export const BOB_MARLEY: Artist = {
|
||||||
@@ -149,6 +154,7 @@ export const BOB_MARLEY: Artist = {
|
|||||||
medium: "http://localhost/BOB_MARLEY/med",
|
medium: "http://localhost/BOB_MARLEY/med",
|
||||||
large: "http://localhost/BOB_MARLEY/lge",
|
large: "http://localhost/BOB_MARLEY/lge",
|
||||||
},
|
},
|
||||||
|
similarArtists: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MADONNA: Artist = {
|
export const MADONNA: Artist = {
|
||||||
@@ -160,6 +166,7 @@ export const MADONNA: Artist = {
|
|||||||
medium: undefined,
|
medium: undefined,
|
||||||
large: "http://localhost/MADONNA/lge",
|
large: "http://localhost/MADONNA/lge",
|
||||||
},
|
},
|
||||||
|
similarArtists: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const METALLICA: Artist = {
|
export const METALLICA: Artist = {
|
||||||
@@ -184,6 +191,7 @@ export const METALLICA: Artist = {
|
|||||||
medium: "http://localhost/METALLICA/med",
|
medium: "http://localhost/METALLICA/med",
|
||||||
large: "http://localhost/METALLICA/lge",
|
large: "http://localhost/METALLICA/lge",
|
||||||
},
|
},
|
||||||
|
similarArtists: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ALL_ARTISTS = [BOB_MARLEY, BLONDIE, MADONNA, METALLICA];
|
export const ALL_ARTISTS = [BOB_MARLEY, BLONDIE, MADONNA, METALLICA];
|
||||||
|
|||||||
@@ -68,15 +68,16 @@ const ok = (data: string) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const artistInfoXml = (
|
const artistInfoXml = (
|
||||||
images: Images
|
artist: Artist,
|
||||||
) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
||||||
<artistInfo>
|
<artistInfo>
|
||||||
<biography></biography>
|
<biography></biography>
|
||||||
<musicBrainzId></musicBrainzId>
|
<musicBrainzId></musicBrainzId>
|
||||||
<lastFmUrl></lastFmUrl>
|
<lastFmUrl></lastFmUrl>
|
||||||
<smallImageUrl>${images.small || ""}</smallImageUrl>
|
<smallImageUrl>${artist.image.small || ""}</smallImageUrl>
|
||||||
<mediumImageUrl>${images.medium || ""}</mediumImageUrl>
|
<mediumImageUrl>${artist.image.medium || ""}</mediumImageUrl>
|
||||||
<largeImageUrl>${images.large || ""}</largeImageUrl>
|
<largeImageUrl>${artist.image.large || ""}</largeImageUrl>
|
||||||
|
${artist.similarArtists.map(it => `<similarArtist id="${it.id}" name="${it.name}" albumCount="3"></similarArtist>`)}
|
||||||
</artistInfo>
|
</artistInfo>
|
||||||
</subsonic-response>`;
|
</subsonic-response>`;
|
||||||
|
|
||||||
@@ -296,205 +297,412 @@ describe("Navidrome", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("getting an artist", () => {
|
describe("getting an artist", () => {
|
||||||
describe("when the artist exists and has dodgy looking artist image uris", () => {
|
describe("when the artist exists", () => {
|
||||||
const album1: Album = anAlbum();
|
describe("and has many similar artists", () => {
|
||||||
|
const album1: Album = anAlbum();
|
||||||
|
|
||||||
const album2: Album = anAlbum();
|
const album2: Album = anAlbum();
|
||||||
|
|
||||||
const artist: Artist = anArtist({
|
const artist: Artist = anArtist({
|
||||||
albums: [album1, album2],
|
albums: [album1, album2],
|
||||||
image: {
|
|
||||||
small: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
|
||||||
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
|
||||||
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(artistXml(artist))))
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(artistInfoXml(artist.image)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return remove the dodgy looking image uris and return undefined", async () => {
|
|
||||||
const result: Artist = await navidrome
|
|
||||||
.generateToken({ username, password })
|
|
||||||
.then((it) => it as AuthSuccess)
|
|
||||||
.then((it) => navidrome.login(it.authToken))
|
|
||||||
.then((it) => it.artist(artist.id));
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
id: artist.id,
|
|
||||||
name: artist.name,
|
|
||||||
image: {
|
image: {
|
||||||
small: undefined,
|
small: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
medium: undefined,
|
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
large: undefined,
|
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
},
|
},
|
||||||
albums: artist.albums,
|
similarArtists: [{ id: "similar1.id", name: "similar1" }, { id: "similar2.id", name: "similar2" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the similar artists", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
|
image: {
|
||||||
|
small: undefined,
|
||||||
|
medium: undefined,
|
||||||
|
large: undefined,
|
||||||
|
},
|
||||||
|
albums: artist.albums,
|
||||||
|
similarArtists: artist.similarArtists
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and has one similar artists", () => {
|
||||||
|
const album1: Album = anAlbum();
|
||||||
|
|
||||||
|
const album2: Album = anAlbum();
|
||||||
|
|
||||||
|
const artist: Artist = anArtist({
|
||||||
|
albums: [album1, album2],
|
||||||
|
image: {
|
||||||
|
small: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
},
|
},
|
||||||
headers,
|
similarArtists: [{ id: "similar1.id", name: "similar1" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the similar artists", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
|
image: {
|
||||||
|
small: undefined,
|
||||||
|
medium: undefined,
|
||||||
|
large: undefined,
|
||||||
|
},
|
||||||
|
albums: artist.albums,
|
||||||
|
similarArtists: artist.similarArtists
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and has no similar artists", () => {
|
||||||
|
const album1: Album = anAlbum();
|
||||||
|
|
||||||
|
const album2: Album = anAlbum();
|
||||||
|
|
||||||
|
const artist: Artist = anArtist({
|
||||||
|
albums: [album1, album2],
|
||||||
|
image: {
|
||||||
|
small: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
},
|
},
|
||||||
headers,
|
similarArtists: [],
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the artist exists and has multiple albums", () => {
|
|
||||||
const album1: Album = anAlbum();
|
|
||||||
|
|
||||||
const album2: Album = anAlbum();
|
|
||||||
|
|
||||||
const artist: Artist = anArtist({
|
|
||||||
albums: [album1, album2],
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(artistXml(artist))))
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(artistInfoXml(artist.image)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return it", async () => {
|
|
||||||
const result: Artist = await navidrome
|
|
||||||
.generateToken({ username, password })
|
|
||||||
.then((it) => it as AuthSuccess)
|
|
||||||
.then((it) => navidrome.login(it.authToken))
|
|
||||||
.then((it) => it.artist(artist.id));
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
id: artist.id,
|
|
||||||
name: artist.name,
|
|
||||||
image: artist.image,
|
|
||||||
albums: artist.albums,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the similar artists", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
|
image: {
|
||||||
|
small: undefined,
|
||||||
|
medium: undefined,
|
||||||
|
large: undefined,
|
||||||
|
},
|
||||||
|
albums: artist.albums,
|
||||||
|
similarArtists: artist.similarArtists
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and has dodgy looking artist image uris", () => {
|
||||||
|
const album1: Album = anAlbum();
|
||||||
|
|
||||||
|
const album2: Album = anAlbum();
|
||||||
|
|
||||||
|
const artist: Artist = anArtist({
|
||||||
|
albums: [album1, album2],
|
||||||
|
image: {
|
||||||
|
small: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
|
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||||
},
|
},
|
||||||
headers,
|
similarArtists: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return remove the dodgy looking image uris and return undefined", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
},
|
image: {
|
||||||
headers,
|
small: undefined,
|
||||||
|
medium: undefined,
|
||||||
|
large: undefined,
|
||||||
|
},
|
||||||
|
albums: artist.albums,
|
||||||
|
similarArtists: []
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the artist exists and has only 1 album", () => {
|
describe("and has multiple albums", () => {
|
||||||
const album: Album = anAlbum();
|
const album1: Album = anAlbum();
|
||||||
|
|
||||||
const artist: Artist = anArtist({
|
const album2: Album = anAlbum();
|
||||||
albums: [album],
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
const artist: Artist = anArtist({
|
||||||
mockGET
|
albums: [album1, album2],
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
similarArtists: []
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(artistXml(artist))))
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(artistInfoXml(artist.image)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return it", async () => {
|
|
||||||
const result: Artist = await navidrome
|
|
||||||
.generateToken({ username, password })
|
|
||||||
.then((it) => it as AuthSuccess)
|
|
||||||
.then((it) => navidrome.login(it.authToken))
|
|
||||||
.then((it) => it.artist(artist.id));
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
id: artist.id,
|
|
||||||
name: artist.name,
|
|
||||||
image: artist.image,
|
|
||||||
albums: artist.albums,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return it", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
},
|
image: artist.image,
|
||||||
headers,
|
albums: artist.albums,
|
||||||
|
similarArtists: []
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and has only 1 album", () => {
|
||||||
|
const album: Album = anAlbum();
|
||||||
|
|
||||||
|
const artist: Artist = anArtist({
|
||||||
|
albums: [album],
|
||||||
|
similarArtists: []
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return it", async () => {
|
||||||
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
},
|
image: artist.image,
|
||||||
headers,
|
albums: artist.albums,
|
||||||
|
similarArtists: []
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the artist exists and has no albums", () => {
|
describe("and has no albums", () => {
|
||||||
const artist: Artist = anArtist({
|
const artist: Artist = anArtist({
|
||||||
albums: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(artistXml(artist))))
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(artistInfoXml(artist.image)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return it", async () => {
|
|
||||||
const result: Artist = await navidrome
|
|
||||||
.generateToken({ username, password })
|
|
||||||
.then((it) => it as AuthSuccess)
|
|
||||||
.then((it) => navidrome.login(it.authToken))
|
|
||||||
.then((it) => it.artist(artist.id));
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
id: artist.id,
|
|
||||||
name: artist.name,
|
|
||||||
image: artist.image,
|
|
||||||
albums: [],
|
albums: [],
|
||||||
|
similarArtists: []
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
beforeEach(() => {
|
||||||
params: {
|
mockGET
|
||||||
id: artist.id,
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
...authParams,
|
.mockImplementationOnce(() =>
|
||||||
},
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
headers,
|
)
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
it("should return it", async () => {
|
||||||
params: {
|
const result: Artist = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.artist(artist.id));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
id: artist.id,
|
id: artist.id,
|
||||||
...authParams,
|
name: artist.name,
|
||||||
},
|
image: artist.image,
|
||||||
headers,
|
albums: [],
|
||||||
|
similarArtists: []
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo`, {
|
||||||
|
params: {
|
||||||
|
id: artist.id,
|
||||||
|
...authParams,
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1388,7 +1596,7 @@ describe("Navidrome", () => {
|
|||||||
data: Buffer.from("the image", "ascii"),
|
data: Buffer.from("the image", "ascii"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const artist = anArtist({ id: artistId });
|
const artist = anArtist({ id: artistId, image: images });
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
@@ -1396,7 +1604,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1454,6 +1662,7 @@ describe("Navidrome", () => {
|
|||||||
const artist = anArtist({
|
const artist = anArtist({
|
||||||
id: artistId,
|
id: artistId,
|
||||||
albums: [album1, album2],
|
albums: [album1, album2],
|
||||||
|
image: images
|
||||||
});
|
});
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
@@ -1462,7 +1671,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1528,7 +1737,7 @@ describe("Navidrome", () => {
|
|||||||
data: Buffer.from("the image", "ascii"),
|
data: Buffer.from("the image", "ascii"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const artist = anArtist({ id: artistId, albums: [] });
|
const artist = anArtist({ id: artistId, albums: [], image: images });
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
@@ -1536,7 +1745,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1595,7 +1804,7 @@ describe("Navidrome", () => {
|
|||||||
data: originalImage,
|
data: originalImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
const artist = anArtist({ id: artistId });
|
const artist = anArtist({ id: artistId, image: images });
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
@@ -1603,13 +1812,15 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
const resize = jest.fn();
|
const resize = jest.fn();
|
||||||
(sharp as unknown as jest.Mock).mockReturnValue({ resize });
|
((sharp as unknown) as jest.Mock).mockReturnValue({ resize });
|
||||||
resize.mockReturnValue({ toBuffer: () => Promise.resolve(resizedImage) })
|
resize.mockReturnValue({
|
||||||
|
toBuffer: () => Promise.resolve(resizedImage),
|
||||||
|
});
|
||||||
|
|
||||||
const result = await navidrome
|
const result = await navidrome
|
||||||
.generateToken({ username, password })
|
.generateToken({ username, password })
|
||||||
@@ -1668,6 +1879,7 @@ describe("Navidrome", () => {
|
|||||||
const artist = anArtist({
|
const artist = anArtist({
|
||||||
id: artistId,
|
id: artistId,
|
||||||
albums: [album1, album2],
|
albums: [album1, album2],
|
||||||
|
image: images
|
||||||
});
|
});
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
@@ -1676,7 +1888,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1743,7 +1955,7 @@ describe("Navidrome", () => {
|
|||||||
data: Buffer.from("the image", "ascii"),
|
data: Buffer.from("the image", "ascii"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const artist = anArtist({ id: artistId, albums: [] });
|
const artist = anArtist({ id: artistId, albums: [], image: images });
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
@@ -1751,7 +1963,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1810,6 +2022,7 @@ describe("Navidrome", () => {
|
|||||||
const artist = anArtist({
|
const artist = anArtist({
|
||||||
id: artistId,
|
id: artistId,
|
||||||
albums: [album1, album2],
|
albums: [album1, album2],
|
||||||
|
image: images
|
||||||
});
|
});
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
@@ -1818,7 +2031,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
@@ -1885,7 +2098,7 @@ describe("Navidrome", () => {
|
|||||||
data: Buffer.from("the image", "ascii"),
|
data: Buffer.from("the image", "ascii"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const artist = anArtist({ id: artistId, albums: [] });
|
const artist = anArtist({ id: artistId, albums: [], image: images });
|
||||||
|
|
||||||
mockGET
|
mockGET
|
||||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
@@ -1893,7 +2106,7 @@ describe("Navidrome", () => {
|
|||||||
Promise.resolve(ok(artistXml(artist)))
|
Promise.resolve(ok(artistXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() =>
|
.mockImplementationOnce(() =>
|
||||||
Promise.resolve(ok(artistInfoXml(images)))
|
Promise.resolve(ok(artistInfoXml(artist)))
|
||||||
)
|
)
|
||||||
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
.mockImplementationOnce(() => Promise.resolve(streamResponse));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user