mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Similar songs (#18)
* Support for getting similarSongs from navidrome * Ability to load topSongs from navidrome * Load artists not in library from navidrome
This commit is contained in:
@@ -34,7 +34,7 @@ import {
|
||||
AlbumQuery,
|
||||
PlaylistSummary,
|
||||
Playlist,
|
||||
ArtistSummary,
|
||||
SimilarArtist,
|
||||
} from "../src/music_service";
|
||||
import {
|
||||
anAlbum,
|
||||
@@ -151,7 +151,7 @@ describe("asURLSearchParams", () => {
|
||||
|
||||
expect(asURLSearchParams(q)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const ok = (data: string) => ({
|
||||
@@ -159,8 +159,13 @@ const ok = (data: string) => ({
|
||||
data,
|
||||
});
|
||||
|
||||
const similarArtistXml = (artistSummary: ArtistSummary) =>
|
||||
`<similarArtist id="${artistSummary.id}" name="${artistSummary.name}" albumCount="3"></similarArtist>`;
|
||||
const similarArtistXml = (similarArtist: SimilarArtist) => {
|
||||
if(similarArtist.inLibrary)
|
||||
return `<similarArtist id="${similarArtist.id}" name="${similarArtist.name}" albumCount="3"></similarArtist>`
|
||||
else
|
||||
return `<similarArtist id="-1" name="${similarArtist.name}" albumCount="3"></similarArtist>`
|
||||
}
|
||||
|
||||
|
||||
const getArtistInfoXml = (
|
||||
artist: Artist
|
||||
@@ -222,19 +227,18 @@ const albumListXml = (
|
||||
) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
||||
<albumList>
|
||||
${albums
|
||||
.map(([artist, album]) => albumXml(artist, album))
|
||||
.join("")}
|
||||
.map(([artist, album]) => albumXml(artist, album))
|
||||
.join("")}
|
||||
</albumList>
|
||||
</subsonic-response>`;
|
||||
|
||||
const artistXml = (artist: Artist) => `<artist id="${artist.id}" name="${
|
||||
artist.name
|
||||
}" albumCount="${artist.albums.length}" artistImageUrl="....">
|
||||
const artistXml = (artist: Artist) => `<artist id="${artist.id}" name="${artist.name
|
||||
}" albumCount="${artist.albums.length}" artistImageUrl="....">
|
||||
${artist.albums
|
||||
.map((album) =>
|
||||
albumXml(artist, album)
|
||||
)
|
||||
.join("")}
|
||||
.map((album) =>
|
||||
albumXml(artist, album)
|
||||
)
|
||||
.join("")}
|
||||
</artist>`;
|
||||
|
||||
const getArtistXml = (
|
||||
@@ -260,20 +264,32 @@ const getAlbumXml = (
|
||||
tracks: Track[]
|
||||
) => `<subsonic-response status="ok" version="1.8.0">
|
||||
${albumXml(
|
||||
artist,
|
||||
album,
|
||||
tracks
|
||||
)}
|
||||
artist,
|
||||
album,
|
||||
tracks
|
||||
)}
|
||||
</subsonic-response>`;
|
||||
|
||||
const getSongXml = (
|
||||
track: Track
|
||||
) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
||||
${songXml(
|
||||
track
|
||||
)}
|
||||
track
|
||||
)}
|
||||
</subsonic-response>`;
|
||||
|
||||
const similarSongsXml = (tracks: Track[]) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
||||
<similarSongs>
|
||||
${tracks.map(songXml).join("")}
|
||||
</similarSongs>
|
||||
</subsonic-response>`
|
||||
|
||||
const topSongsXml = (tracks: Track[]) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.40.0 (8799358a)">
|
||||
<topSongs>
|
||||
${tracks.map(songXml).join("")}
|
||||
</topSongs>
|
||||
</subsonic-response>`
|
||||
|
||||
export type ArtistWithAlbum = {
|
||||
artist: Artist;
|
||||
album: Album;
|
||||
@@ -291,7 +307,10 @@ const getPlayLists = (
|
||||
</subsonic-response>`;
|
||||
|
||||
const error = (code: string, message: string) =>
|
||||
`<subsonic-response xmlns="http://subsonic.org/restapi" status="failed" version="1.16.1" type="navidrome" serverVersion="0.42.0 (f1bd736b)"><error code="${code}" message="${message}"></error></subsonic-response>`;
|
||||
`<subsonic-response xmlns="http://subsonic.org/restapi" status="failed" version="1.16.1" type="navidrome" serverVersion="0.42.0 (f1bd736b)">
|
||||
<error code="${code}" message="${message}">
|
||||
</error>
|
||||
</subsonic-response>`;
|
||||
|
||||
const createPlayList = (playlist: PlaylistSummary) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.42.0 (f1bd736b)">
|
||||
${playlistXml(playlist)}
|
||||
@@ -300,9 +319,8 @@ const createPlayList = (playlist: PlaylistSummary) => `<subsonic-response xmlns=
|
||||
const getPlayList = (
|
||||
playlist: Playlist
|
||||
) => `<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.42.0 (f1bd736b)">
|
||||
<playlist id="${playlist.id}" name="${playlist.name}" songCount="${
|
||||
playlist.entries.length
|
||||
}" duration="627" public="true" owner="bob" created="2021-05-06T02:07:30.460465988Z" changed="2021-05-06T02:40:04Z">
|
||||
<playlist id="${playlist.id}" name="${playlist.name}" songCount="${playlist.entries.length
|
||||
}" duration="627" public="true" owner="bob" created="2021-05-06T02:07:30.460465988Z" changed="2021-05-06T02:40:04Z">
|
||||
${playlist.entries
|
||||
.map(
|
||||
(it) => `<entry
|
||||
@@ -500,8 +518,10 @@ describe("Navidrome", () => {
|
||||
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||
},
|
||||
similarArtists: [
|
||||
{ id: "similar1.id", name: "similar1" },
|
||||
{ id: "similar2.id", name: "similar2" },
|
||||
{ id: "similar1.id", name: "similar1", inLibrary: true },
|
||||
{ id: "-1", name: "similar2", inLibrary: false },
|
||||
{ id: "similar3.id", name: "similar3", inLibrary: true },
|
||||
{ id: "-1", name: "similar4", inLibrary: false },
|
||||
],
|
||||
});
|
||||
|
||||
@@ -536,7 +556,7 @@ describe("Navidrome", () => {
|
||||
});
|
||||
|
||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
|
||||
params:asURLSearchParams( {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
}),
|
||||
@@ -547,14 +567,15 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and has one similar artists", () => {
|
||||
describe("and has one similar artist", () => {
|
||||
const album1: Album = anAlbum({ genre: asGenre("G1") });
|
||||
|
||||
const album2: Album = anAlbum({ genre: asGenre("G2") });
|
||||
@@ -566,7 +587,7 @@ describe("Navidrome", () => {
|
||||
medium: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||
large: `http://localhost:80/${DODGY_IMAGE_NAME}`,
|
||||
},
|
||||
similarArtists: [{ id: "similar1.id", name: "similar1" }],
|
||||
similarArtists: [{ id: "similar1.id", name: "similar1", inLibrary: true }],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -611,7 +632,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -675,7 +697,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -739,7 +762,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -794,7 +818,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -847,7 +872,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -898,7 +924,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artist.id,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -2087,7 +2114,7 @@ describe("Navidrome", () => {
|
||||
|
||||
expect(streamClientApplication).toHaveBeenCalledWith(track);
|
||||
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/stream`, {
|
||||
params:asURLSearchParams( {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: trackId,
|
||||
c: clientApplication,
|
||||
@@ -2231,7 +2258,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2307,7 +2335,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2383,7 +2412,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2452,7 +2482,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2531,7 +2562,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2608,7 +2640,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2680,7 +2713,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -2757,7 +2791,8 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id: artistId,
|
||||
count: 50
|
||||
count: 50,
|
||||
includeNotPresent: true
|
||||
}),
|
||||
headers,
|
||||
}
|
||||
@@ -3343,7 +3378,7 @@ describe("Navidrome", () => {
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(error("70", "not there")))
|
||||
Promise.resolve(ok(error("70", "data not found")))
|
||||
);
|
||||
|
||||
return expect(
|
||||
@@ -3352,7 +3387,7 @@ describe("Navidrome", () => {
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.playlist(id))
|
||||
).rejects.toEqual("not there");
|
||||
).rejects.toEqual("data not found");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3447,26 +3482,26 @@ describe("Navidrome", () => {
|
||||
const id = uuid();
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(createPlayList({id, name})))
|
||||
);
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(createPlayList({ id, name })))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.createPlaylist(name));
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.createPlaylist(name));
|
||||
|
||||
expect(result).toEqual({ id, name });
|
||||
expect(result).toEqual({ id, name });
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/createPlaylist`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
name,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/createPlaylist`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
name,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3475,26 +3510,26 @@ describe("Navidrome", () => {
|
||||
const id = "id-to-delete";
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(EMPTY))
|
||||
);
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(EMPTY))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.deletePlaylist(id));
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.deletePlaylist(id));
|
||||
|
||||
expect(result).toEqual(true);
|
||||
expect(result).toEqual(true);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/deletePlaylist`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/deletePlaylist`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3522,7 +3557,7 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
playlistId,
|
||||
songIdToAdd: trackId,
|
||||
songIdToAdd: trackId,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
@@ -3532,7 +3567,7 @@ describe("Navidrome", () => {
|
||||
describe("removing a track from a playlist", () => {
|
||||
it("should remove it", async () => {
|
||||
const playlistId = uuid();
|
||||
const indicies =[6, 100, 33];
|
||||
const indicies = [6, 100, 33];
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
@@ -3552,12 +3587,334 @@ describe("Navidrome", () => {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
playlistId,
|
||||
songIndexToRemove: indicies,
|
||||
songIndexToRemove: indicies,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("similarSongs", () => {
|
||||
describe("when there is one similar songs", () => {
|
||||
it("should return it", async () => {
|
||||
const id = "idWithTracks";
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album1 = anAlbum({ id: "album1", name: "Burnin", genre: pop });
|
||||
const artist1 = anArtist({
|
||||
id: "artist1",
|
||||
name: "Bob Marley",
|
||||
albums: [album1],
|
||||
});
|
||||
|
||||
const track1 = aTrack({
|
||||
id: "track1",
|
||||
artist: artistToArtistSummary(artist1),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(similarSongsXml([track1])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist1, album1, [])))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.similarSongs(id));
|
||||
|
||||
expect(result).toEqual([track1]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there are similar songs", () => {
|
||||
it("should return them", async () => {
|
||||
const id = "idWithTracks";
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album1 = anAlbum({ id: "album1", name: "Burnin", genre: pop });
|
||||
const artist1 = anArtist({
|
||||
id: "artist1",
|
||||
name: "Bob Marley",
|
||||
albums: [album1],
|
||||
});
|
||||
|
||||
const album2 = anAlbum({ id: "album2", name: "Walking", genre: pop });
|
||||
const artist2 = anArtist({
|
||||
id: "artist2",
|
||||
name: "Bob Jane",
|
||||
albums: [album2],
|
||||
});
|
||||
|
||||
const track1 = aTrack({
|
||||
id: "track1",
|
||||
artist: artistToArtistSummary(artist1),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
const track2 = aTrack({
|
||||
id: "track2",
|
||||
artist: artistToArtistSummary(artist2),
|
||||
album: albumToAlbumSummary(album2),
|
||||
genre: pop
|
||||
});
|
||||
const track3 = aTrack({
|
||||
id: "track3",
|
||||
artist: artistToArtistSummary(artist1),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(similarSongsXml([track1, track2, track3])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist1, album1, [])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist2, album2, [])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist1, album1, [])))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.similarSongs(id));
|
||||
|
||||
expect(result).toEqual([track1, track2, track3]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there are no similar songs", () => {
|
||||
it("should return []", async () => {
|
||||
const id = "idWithNoTracks";
|
||||
|
||||
const xml = similarSongsXml([]);
|
||||
console.log(`xml = ${xml}`)
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(xml))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.similarSongs(id));
|
||||
|
||||
expect(result).toEqual([]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
id,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there id doesnt exist", () => {
|
||||
it("should fail", async () => {
|
||||
const id = "idThatHasAnError";
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(error("70", "data not found")))
|
||||
);
|
||||
|
||||
return expect(navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.similarSongs(id))).rejects.toEqual("data not found");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("topSongs", () => {
|
||||
describe("when there is one top song", () => {
|
||||
it("should return it", async () => {
|
||||
const artistId = "bobMarleyId";
|
||||
const artistName = "Bob Marley";
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album1 = anAlbum({ name: "Burnin", genre: pop });
|
||||
const artist = anArtist({
|
||||
id: artistId,
|
||||
name: artistName,
|
||||
albums: [album1],
|
||||
});
|
||||
|
||||
const track1 = aTrack({
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getArtistXml(artist)))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(topSongsXml([track1])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist, album1, [])))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.topSongs(artistId));
|
||||
|
||||
expect(result).toEqual([track1]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
artist: artistName,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there are many top songs", () => {
|
||||
it("should return them", async () => {
|
||||
const artistId = "bobMarleyId";
|
||||
const artistName = "Bob Marley";
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album1 = anAlbum({ name: "Burnin", genre: pop });
|
||||
const album2 = anAlbum({ name: "Churning", genre: pop });
|
||||
|
||||
const artist = anArtist({
|
||||
id: artistId,
|
||||
name: artistName,
|
||||
albums: [album1, album2],
|
||||
});
|
||||
|
||||
const track1 = aTrack({
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
const track2 = aTrack({
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album2),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
const track3 = aTrack({
|
||||
artist: artistToArtistSummary(artist),
|
||||
album: albumToAlbumSummary(album1),
|
||||
genre: pop
|
||||
});
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getArtistXml(artist)))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(topSongsXml([track1, track2, track3])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist, album1, [])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist, album2, [])))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getAlbumXml(artist, album1, [])))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.topSongs(artistId));
|
||||
|
||||
expect(result).toEqual([track1, track2, track3]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
artist: artistName,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there are no similar songs", () => {
|
||||
it("should return []", async () => {
|
||||
const artistId = "bobMarleyId";
|
||||
const artistName = "Bob Marley";
|
||||
const pop = asGenre("Pop");
|
||||
|
||||
const album1 = anAlbum({ name: "Burnin", genre: pop });
|
||||
const artist = anArtist({
|
||||
id: artistId,
|
||||
name: artistName,
|
||||
albums: [album1],
|
||||
});
|
||||
|
||||
mockGET
|
||||
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||
.mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(getArtistXml(artist)))
|
||||
).mockImplementationOnce(() =>
|
||||
Promise.resolve(ok(topSongsXml([])))
|
||||
);
|
||||
|
||||
const result = await navidrome
|
||||
.generateToken({ username, password })
|
||||
.then((it) => it as AuthSuccess)
|
||||
.then((it) => navidrome.login(it.authToken))
|
||||
.then((it) => it.topSongs(artistId));
|
||||
|
||||
expect(result).toEqual([]);
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
artist: artistName,
|
||||
count: 50,
|
||||
}),
|
||||
headers,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user