Genre with id and name, rather than just name

This commit is contained in:
simojenki
2021-03-19 20:31:39 +11:00
parent 852cc34a43
commit 0e3fd9d781
8 changed files with 168 additions and 112 deletions

View File

@@ -49,18 +49,23 @@ export type AlbumSummary = {
id: string; id: string;
name: string; name: string;
year: string | undefined; year: string | undefined;
genre: string | undefined; genre: Genre | undefined;
}; };
export type Album = AlbumSummary & {}; export type Album = AlbumSummary & {};
export type Genre = {
name: string;
id: string;
}
export type Track = { export type Track = {
id: string; id: string;
name: string; name: string;
mimeType: string; mimeType: string;
duration: number; duration: number;
number: number | undefined; number: number | undefined;
genre: string | undefined; genre: Genre | undefined;
album: AlbumSummary; album: AlbumSummary;
artist: ArtistSummary; artist: ArtistSummary;
}; };
@@ -137,7 +142,7 @@ export interface MusicLibrary {
album(id: string): Promise<Album>; album(id: string): Promise<Album>;
tracks(albumId: string): Promise<Track[]>; tracks(albumId: string): Promise<Track[]>;
track(trackId: string): Promise<Track>; track(trackId: string): Promise<Track>;
genres(): Promise<string[]>; genres(): Promise<Genre[]>;
stream({ stream({
trackId, trackId,
range, range,

View File

@@ -17,6 +17,7 @@ import {
Images, Images,
AlbumSummary, AlbumSummary,
NO_IMAGES, NO_IMAGES,
Genre,
} from "./music_service"; } from "./music_service";
import X2JS from "x2js"; import X2JS from "x2js";
import sharp from "sharp"; import sharp from "sharp";
@@ -193,7 +194,7 @@ const asTrack = (album: Album, song: song) => ({
mimeType: song._contentType, mimeType: song._contentType,
duration: parseInt(song._duration || "0"), duration: parseInt(song._duration || "0"),
number: parseInt(song._track || "0"), number: parseInt(song._track || "0"),
genre: song._genre, genre: maybeAsGenre(song._genre),
album, album,
artist: { artist: {
id: song._artistId, id: song._artistId,
@@ -206,9 +207,18 @@ const asAlbum = (album: album) => ({
id: album._id, id: album._id,
name: album._name, name: album._name,
year: album._year, year: album._year,
genre: album._genre, genre: maybeAsGenre(album._genre),
}); });
export const asGenre = (genreName: string) => ({ id: genreName, name: genreName });
const maybeAsGenre = (genreName: string | undefined): Genre | undefined =>
pipe(
O.fromNullable(genreName),
O.map(asGenre),
O.getOrElseW(() => undefined)
);
export class Navidrome implements MusicService { export class Navidrome implements MusicService {
url: string; url: string;
encryption: Encryption; encryption: Encryption;
@@ -318,7 +328,7 @@ export class Navidrome implements MusicService {
id: album._id, id: album._id,
name: album._name, name: album._name,
year: album._year, year: album._year,
genre: album._genre, genre: maybeAsGenre(album._genre),
})); }));
getArtist = ( getArtist = (
@@ -336,7 +346,7 @@ export class Navidrome implements MusicService {
id: album._id, id: album._id,
name: album._name, name: album._name,
year: album._year, year: album._year,
genre: album._genre, genre: maybeAsGenre(album._genre),
})), })),
})); }));
@@ -399,7 +409,7 @@ export class Navidrome implements MusicService {
id: album._id, id: album._id,
name: album._name, name: album._name,
year: album._year, year: album._year,
genre: album._genre, genre: maybeAsGenre(album._genre),
})) }))
) )
.then(slice2(q)) .then(slice2(q))
@@ -416,7 +426,8 @@ export class Navidrome implements MusicService {
pipe( pipe(
it.genres.genre, it.genres.genre,
A.map((it) => it.__text), A.map((it) => it.__text),
A.sort(ordString) A.sort(ordString),
A.map((it) => ({ id: it, name: it }))
) )
), ),
tracks: (albumId: string) => tracks: (albumId: string) =>

View File

@@ -10,6 +10,7 @@ import {
Album, Album,
AlbumSummary, AlbumSummary,
ArtistSummary, ArtistSummary,
Genre,
MusicLibrary, MusicLibrary,
MusicService, MusicService,
slice2, slice2,
@@ -184,10 +185,10 @@ const container = ({
title, title,
}); });
const genre = (genre: string) => ({ const genre = (genre: Genre) => ({
itemType: "container", itemType: "container",
id: `genre:${genre}`, id: `genre:${genre.id}`,
title: genre, title: genre.name,
}); });
export const defaultAlbumArtURI = ( export const defaultAlbumArtURI = (
@@ -235,8 +236,8 @@ export const track = (
artist: track.artist.name, artist: track.artist.name,
artistId: track.artist.id, artistId: track.artist.id,
duration: track.duration, duration: track.duration,
genre: track.album.genre, genre: track.album.genre?.name,
// genreId genreId: track.album.genre?.id,
trackNumber: track.number, trackNumber: track.number,
}, },
}); });

View File

@@ -80,15 +80,26 @@ export function anArtist(fields: Partial<Artist> = {}): Artist {
large: `/artist/art/${id}/large`, large: `/artist/art/${id}/large`,
}, },
similarArtists: [ similarArtists: [
{ id: uuid(), name: "Similar artist1"}, { id: uuid(), name: "Similar artist1" },
{ id: uuid(), name: "Similar artist2"}, { id: uuid(), name: "Similar artist2" },
], ],
...fields, ...fields,
}; };
} }
export const SAMPLE_GENRES = ["Metal", "Pop", "Rock", "Hip-Hop"] export const HIP_HOP = { id: "genre_hip_hop", name: "Hip-Hop" };
export const randomGenre = () => SAMPLE_GENRES[randomInt(SAMPLE_GENRES.length)] export const METAL = { id: "genre_metal", name: "Metal" };
export const NEW_WAVE = { id: "genre_new_wave", name: "New Wave" };
export const POP = { id: "genre_pop", name: "Pop" };
export const POP_ROCK = { id: "genre_pop_rock", name: "Pop Rock" };
export const REGGAE = { id: "genre_reggae", name: "Reggae" };
export const ROCK = { id: "genre_rock", name: "Rock" };
export const SKA = { id: "genre_ska", name: "Ska" };
export const PUNK = { id: "genre_punk", name: "Punk" };
export const TRIP_HOP = { id: "genre_trip_hop", name: "Trip Hop" };
export const SAMPLE_GENRES = [HIP_HOP, METAL, NEW_WAVE, POP, POP_ROCK, REGGAE, ROCK, SKA];
export const randomGenre = () => SAMPLE_GENRES[randomInt(SAMPLE_GENRES.length)];
export function aTrack(fields: Partial<Track> = {}): Track { export function aTrack(fields: Partial<Track> = {}): Track {
const id = uuid(); const id = uuid();
@@ -101,8 +112,8 @@ export function aTrack(fields: Partial<Track> = {}): Track {
genre: randomGenre(), genre: randomGenre(),
artist: anArtist(), artist: anArtist(),
album: anAlbum(), album: anAlbum(),
...fields ...fields,
} };
} }
export function anAlbum(fields: Partial<Album> = {}): Album { export function anAlbum(fields: Partial<Album> = {}): Album {
@@ -124,13 +135,13 @@ export const BLONDIE: Artist = {
id: uuid(), id: uuid(),
name: "Blondie", name: "Blondie",
year: "1976", year: "1976",
genre: "New Wave", genre: NEW_WAVE,
}, },
{ {
id: uuid(), id: uuid(),
name: "Parallel Lines", name: "Parallel Lines",
year: "1978", year: "1978",
genre: "Pop Rock", genre: POP_ROCK,
}, },
], ],
image: { image: {
@@ -138,23 +149,23 @@ export const BLONDIE: Artist = {
medium: undefined, medium: undefined,
large: undefined, large: undefined,
}, },
similarArtists: [] similarArtists: [],
}; };
export const BOB_MARLEY: Artist = { export const BOB_MARLEY: Artist = {
id: uuid(), id: uuid(),
name: "Bob Marley", name: "Bob Marley",
albums: [ albums: [
{ id: uuid(), name: "Burin'", year: "1973", genre: "Reggae", }, { id: uuid(), name: "Burin'", year: "1973", genre: REGGAE },
{ id: uuid(), name: "Exodus", year: "1977", genre: "Reggae", }, { id: uuid(), name: "Exodus", year: "1977", genre: REGGAE },
{ id: uuid(), name: "Kaya", year: "1978", genre: "Ska", }, { id: uuid(), name: "Kaya", year: "1978", genre: SKA },
], ],
image: { image: {
small: "http://localhost/BOB_MARLEY/sml", small: "http://localhost/BOB_MARLEY/sml",
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: [] similarArtists: [],
}; };
export const MADONNA: Artist = { export const MADONNA: Artist = {
@@ -166,7 +177,7 @@ export const MADONNA: Artist = {
medium: undefined, medium: undefined,
large: "http://localhost/MADONNA/lge", large: "http://localhost/MADONNA/lge",
}, },
similarArtists: [] similarArtists: [],
}; };
export const METALLICA: Artist = { export const METALLICA: Artist = {
@@ -177,13 +188,13 @@ export const METALLICA: Artist = {
id: uuid(), id: uuid(),
name: "Ride the Lightening", name: "Ride the Lightening",
year: "1984", year: "1984",
genre: "Heavy Metal", genre: METAL,
}, },
{ {
id: uuid(), id: uuid(),
name: "Master of Puppets", name: "Master of Puppets",
year: "1986", year: "1986",
genre: "Heavy Metal", genre: METAL,
}, },
], ],
image: { image: {
@@ -191,7 +202,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: [] similarArtists: [],
}; };
export const ALL_ARTISTS = [BOB_MARLEY, BLONDIE, MADONNA, METALLICA]; export const ALL_ARTISTS = [BOB_MARLEY, BLONDIE, MADONNA, METALLICA];

View File

@@ -6,7 +6,7 @@ import {
albumToAlbumSummary, albumToAlbumSummary,
} from "../src/music_service"; } from "../src/music_service";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { anArtist, anAlbum, aTrack } from "./builders"; import { anArtist, anAlbum, aTrack, POP, ROCK, METAL, HIP_HOP, SKA } from "./builders";
describe("InMemoryMusicService", () => { describe("InMemoryMusicService", () => {
const service = new InMemoryMusicService(); const service = new InMemoryMusicService();
@@ -190,16 +190,16 @@ describe("InMemoryMusicService", () => {
}); });
describe("albums", () => { describe("albums", () => {
const artist1_album1 = anAlbum({ genre: "Pop" }); const artist1_album1 = anAlbum({ genre: POP });
const artist1_album2 = anAlbum({ genre: "Rock" }); const artist1_album2 = anAlbum({ genre: ROCK });
const artist1_album3 = anAlbum({ genre: "Metal" }); const artist1_album3 = anAlbum({ genre: METAL });
const artist1_album4 = anAlbum({ genre: "Pop" }); const artist1_album4 = anAlbum({ genre: POP });
const artist1_album5 = anAlbum({ genre: "Pop" }); const artist1_album5 = anAlbum({ genre: POP });
const artist2_album1 = anAlbum({ genre: "Metal" }); const artist2_album1 = anAlbum({ genre: METAL });
const artist3_album1 = anAlbum({ genre: "Hip-Hop" }); const artist3_album1 = anAlbum({ genre: HIP_HOP });
const artist3_album2 = anAlbum({ genre: "Pop" }); const artist3_album2 = anAlbum({ genre: POP });
const totalAlbumCount = 8; const totalAlbumCount = 8;
@@ -279,7 +279,7 @@ describe("InMemoryMusicService", () => {
it("should return all the albums of that genre for all the artists", async () => { it("should return all the albums of that genre for all the artists", async () => {
expect( expect(
await musicLibrary.albums({ await musicLibrary.albums({
genre: "Pop", genre: POP.id,
_index: 0, _index: 0,
_count: 100, _count: 100,
}) })
@@ -300,7 +300,7 @@ describe("InMemoryMusicService", () => {
it("should return only the albums for that page", async () => { it("should return only the albums for that page", async () => {
expect( expect(
await musicLibrary.albums({ await musicLibrary.albums({
genre: "Pop", genre: POP.id,
_index: 1, _index: 1,
_count: 2, _count: 2,
}) })
@@ -318,7 +318,7 @@ describe("InMemoryMusicService", () => {
it("should return only the albums for the last page", async () => { it("should return only the albums for the last page", async () => {
expect( expect(
await musicLibrary.albums({ await musicLibrary.albums({
genre: "Pop", genre: POP.id,
_index: 3, _index: 3,
_count: 100, _count: 100,
}) })
@@ -367,16 +367,16 @@ describe("InMemoryMusicService", () => {
describe("genres", () => { describe("genres", () => {
const artist1 = anArtist({ const artist1 = anArtist({
albums: [ albums: [
anAlbum({ genre: "Pop" }), anAlbum({ genre: POP }),
anAlbum({ genre: "Rock" }), anAlbum({ genre: ROCK }),
anAlbum({ genre: "Pop" }), anAlbum({ genre: POP }),
], ],
}); });
const artist2 = anArtist({ const artist2 = anArtist({
albums: [ albums: [
anAlbum({ genre: "Hip-Hop" }), anAlbum({ genre: HIP_HOP }),
anAlbum({ genre: "Rap" }), anAlbum({ genre: SKA }),
anAlbum({ genre: "Pop" }), anAlbum({ genre: POP }),
], ],
}); });
@@ -387,10 +387,10 @@ describe("InMemoryMusicService", () => {
describe("fetching all in one page", () => { describe("fetching all in one page", () => {
it("should provide an array of artists", async () => { it("should provide an array of artists", async () => {
expect(await musicLibrary.genres()).toEqual([ expect(await musicLibrary.genres()).toEqual([
"Hip-Hop", HIP_HOP,
"Pop", POP,
"Rap", ROCK,
"Rock", SKA,
]); ]);
}); });
}); });

View File

@@ -1,8 +1,8 @@
import { option as O } from "fp-ts"; import { option as O } from "fp-ts";
import * as A from "fp-ts/Array"; import * as A from "fp-ts/Array";
import { eqString } from "fp-ts/lib/Eq"; import { fromEquals } from "fp-ts/lib/Eq";
import { pipe } from "fp-ts/lib/function"; import { pipe } from "fp-ts/lib/function";
import { ordString } from "fp-ts/lib/Ord"; import { ordString, fromCompare } from "fp-ts/lib/Ord";
import { import {
MusicService, MusicService,
@@ -19,13 +19,14 @@ import {
albumToAlbumSummary, albumToAlbumSummary,
Album, Album,
Track, Track,
Genre,
} from "../src/music_service"; } from "../src/music_service";
type P<T> = (t: T) => boolean; type P<T> = (t: T) => boolean;
const all: P<any> = (_: any) => true; const all: P<any> = (_: any) => true;
const albumWithGenre = (genre: string): P<[Artist, Album]> => ([_, album]) => const albumWithGenre = (genreId: string): P<[Artist, Album]> => ([_, album]) =>
album.genre === genre; album.genre?.id === genreId;
export class InMemoryMusicService implements MusicService { export class InMemoryMusicService implements MusicService {
users: Record<string, string> = {}; users: Record<string, string> = {};
@@ -103,8 +104,10 @@ export class InMemoryMusicService implements MusicService {
A.flatten, A.flatten,
A.map((it) => O.fromNullable(it.genre)), A.map((it) => O.fromNullable(it.genre)),
A.compact, A.compact,
A.uniq(eqString), A.uniq(fromEquals((x, y) => x.id === y.id)),
A.sort(ordString) A.sort(
fromCompare<Genre>((x, y) => ordString.compare(x.id, y.id))
)
) )
), ),
tracks: (albumId: string) => tracks: (albumId: string) =>

View File

@@ -7,6 +7,7 @@ import {
t, t,
BROWSER_HEADERS, BROWSER_HEADERS,
DODGY_IMAGE_NAME, DODGY_IMAGE_NAME,
asGenre
} from "../src/navidrome"; } from "../src/navidrome";
import encryption from "../src/encryption"; import encryption from "../src/encryption";
@@ -93,7 +94,7 @@ const albumXml = (
isDir="true" isDir="true"
title="${album.name}" name="${album.name}" album="${album.name}" title="${album.name}" name="${album.name}" album="${album.name}"
artist="${artist.name}" artist="${artist.name}"
genre="${album.genre}" genre="${album.genre?.name}"
coverArt="foo" coverArt="foo"
duration="123" duration="123"
playCount="4" playCount="4"
@@ -110,7 +111,7 @@ const songXml = (track: Track) => `<song
album="${track.album.name}" album="${track.album.name}"
artist="${track.artist.name}" artist="${track.artist.name}"
track="${track.number}" track="${track.number}"
genre="${track.genre}" genre="${track.genre?.name}"
isDir="false" isDir="false"
coverArt="71381" coverArt="71381"
created="2004-11-08T23:36:11" created="2004-11-08T23:36:11"
@@ -251,7 +252,8 @@ describe("Navidrome", () => {
describe("getting genres", () => { describe("getting genres", () => {
describe("when there is only 1", () => { describe("when there is only 1", () => {
const genres = ["HipHop"]; const genres = ["genre1"];
beforeEach(() => { beforeEach(() => {
mockGET mockGET
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK))) .mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
@@ -265,7 +267,7 @@ describe("Navidrome", () => {
.then((it) => navidrome.login(it.authToken)) .then((it) => navidrome.login(it.authToken))
.then((it) => it.genres()); .then((it) => it.genres());
expect(result).toEqual(genres.sort()); expect(result).toEqual(genres.map(asGenre));
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, { expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, {
params: { params: {
@@ -277,7 +279,7 @@ describe("Navidrome", () => {
}); });
describe("when there are many", () => { describe("when there are many", () => {
const genres = ["HipHop", "Rap", "TripHop", "Pop", "Rock"]; const genres = ["g1", "g2", "g3", "g3"]
beforeEach(() => { beforeEach(() => {
mockGET mockGET
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK))) .mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
@@ -291,7 +293,7 @@ describe("Navidrome", () => {
.then((it) => navidrome.login(it.authToken)) .then((it) => navidrome.login(it.authToken))
.then((it) => it.genres()); .then((it) => it.genres());
expect(result).toEqual(genres.sort()); expect(result).toEqual(genres.map(asGenre));
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, { expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, {
params: { params: {
@@ -306,9 +308,9 @@ describe("Navidrome", () => {
describe("getting an artist", () => { describe("getting an artist", () => {
describe("when the artist exists", () => { describe("when the artist exists", () => {
describe("and has many similar artists", () => { describe("and has many similar artists", () => {
const album1: Album = anAlbum(); const album1: Album = anAlbum({ genre: asGenre("Pop") });
const album2: Album = anAlbum(); const album2: Album = anAlbum({ genre: asGenre("Pop") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album1, album2], albums: [album1, album2],
@@ -372,9 +374,9 @@ describe("Navidrome", () => {
}); });
describe("and has one similar artists", () => { describe("and has one similar artists", () => {
const album1: Album = anAlbum(); const album1: Album = anAlbum({ genre: asGenre("G1") });
const album2: Album = anAlbum(); const album2: Album = anAlbum({ genre: asGenre("G2") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album1, album2], albums: [album1, album2],
@@ -435,9 +437,9 @@ describe("Navidrome", () => {
}); });
describe("and has no similar artists", () => { describe("and has no similar artists", () => {
const album1: Album = anAlbum(); const album1: Album = anAlbum({ genre: asGenre("Jock") });
const album2: Album = anAlbum(); const album2: Album = anAlbum({ genre: asGenre("Mock") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album1, album2], albums: [album1, album2],
@@ -498,9 +500,9 @@ describe("Navidrome", () => {
}); });
describe("and has dodgy looking artist image uris", () => { describe("and has dodgy looking artist image uris", () => {
const album1: Album = anAlbum(); const album1: Album = anAlbum({ genre: asGenre("Pop") });
const album2: Album = anAlbum(); const album2: Album = anAlbum({ genre: asGenre("Flop") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album1, album2], albums: [album1, album2],
@@ -561,9 +563,9 @@ describe("Navidrome", () => {
}); });
describe("and has multiple albums", () => { describe("and has multiple albums", () => {
const album1: Album = anAlbum(); const album1: Album = anAlbum({ genre: asGenre("Pop") });
const album2: Album = anAlbum(); const album2: Album = anAlbum({ genre: asGenre("Flop") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album1, album2], albums: [album1, album2],
@@ -615,7 +617,7 @@ describe("Navidrome", () => {
}); });
describe("and has only 1 album", () => { describe("and has only 1 album", () => {
const album: Album = anAlbum(); const album: Album = anAlbum({ genre: asGenre("Pop") });
const artist: Artist = anArtist({ const artist: Artist = anArtist({
albums: [album], albums: [album],
@@ -842,9 +844,9 @@ describe("Navidrome", () => {
describe("getting albums", () => { describe("getting albums", () => {
describe("filtering", () => { describe("filtering", () => {
const album1 = anAlbum({ genre: "Pop" }); const album1 = anAlbum({ genre: asGenre("Pop") });
const album2 = anAlbum({ genre: "Rock" }); const album2 = anAlbum({ genre: asGenre("Rock") });
const album3 = anAlbum({ genre: "Pop" }); const album3 = anAlbum({ genre: asGenre("Pop") });
const artist = anArtist({ albums: [album1, album2, album3] }); const artist = anArtist({ albums: [album1, album2, album3] });
@@ -894,7 +896,7 @@ describe("Navidrome", () => {
describe("when the artist has only 1 album", () => { describe("when the artist has only 1 album", () => {
const artist1 = anArtist({ const artist1 = anArtist({
name: "one hit wonder", name: "one hit wonder",
albums: [anAlbum()], albums: [anAlbum({ genre: asGenre("Pop") })],
}); });
const artists = [artist1]; const artists = [artist1];
const albums = artists.flatMap((artist) => artist.albums); const albums = artists.flatMap((artist) => artist.albums);
@@ -974,13 +976,17 @@ describe("Navidrome", () => {
}); });
describe("when there are less than 500 albums", () => { describe("when there are less than 500 albums", () => {
const genre1 = asGenre("genre1");
const genre2 = asGenre("genre2");
const genre3 = asGenre("genre3");
const artist1 = anArtist({ const artist1 = anArtist({
name: "abba", name: "abba",
albums: [anAlbum(), anAlbum(), anAlbum()], albums: [anAlbum({ genre: genre1 }), anAlbum({ genre: genre2 }), anAlbum({ genre: genre3 })],
}); });
const artist2 = anArtist({ const artist2 = anArtist({
name: "babba", name: "babba",
albums: [anAlbum(), anAlbum(), anAlbum()], albums: [anAlbum({ genre: genre1 }), anAlbum({ genre: genre2 }), anAlbum({ genre: genre3 })],
}); });
const artists = [artist1, artist2]; const artists = [artist1, artist2];
const albums = artists.flatMap((artist) => artist.albums); const albums = artists.flatMap((artist) => artist.albums);
@@ -1048,7 +1054,7 @@ describe("Navidrome", () => {
describe("when there are more than 500 albums", () => { describe("when there are more than 500 albums", () => {
const first500Albums = range(500).map((i) => const first500Albums = range(500).map((i) =>
anAlbum({ name: `album ${i}` }) anAlbum({ name: `album ${i}`, genre: asGenre(`genre ${i}`) })
); );
const artist = anArtist({ const artist = anArtist({
name: "> 500 albums", name: "> 500 albums",
@@ -1101,15 +1107,17 @@ describe("Navidrome", () => {
describe("getting an album", () => { describe("getting an album", () => {
describe("when it exists", () => { describe("when it exists", () => {
const album = anAlbum(); const genre = asGenre("Pop");
const album = anAlbum({ genre });
const artist = anArtist({ albums: [album] }); const artist = anArtist({ albums: [album] });
const tracks = [ const tracks = [
aTrack({ artist, album }), aTrack({ artist, album, genre }),
aTrack({ artist, album }), aTrack({ artist, album, genre }),
aTrack({ artist, album }), aTrack({ artist, album, genre }),
aTrack({ artist, album }), aTrack({ artist, album, genre }),
]; ];
beforeEach(() => { beforeEach(() => {
@@ -1143,7 +1151,10 @@ describe("Navidrome", () => {
describe("getting tracks", () => { describe("getting tracks", () => {
describe("for an album", () => { describe("for an album", () => {
describe("when the album has multiple tracks", () => { describe("when the album has multiple tracks", () => {
const album = anAlbum({ id: "album1", name: "Burnin" }); const hipHop = asGenre("Hip-Hop")
const tripHop = asGenre("Trip-Hop")
const album = anAlbum({ id: "album1", name: "Burnin", genre: hipHop });
const albumSummary = albumToAlbumSummary(album); const albumSummary = albumToAlbumSummary(album);
const artist = anArtist({ const artist = anArtist({
@@ -1157,10 +1168,10 @@ describe("Navidrome", () => {
}; };
const tracks = [ const tracks = [
aTrack({ artist: artistSummary, album: albumSummary }), aTrack({ artist: artistSummary, album: albumSummary, genre: hipHop }),
aTrack({ artist: artistSummary, album: albumSummary }), aTrack({ artist: artistSummary, album: albumSummary, genre: hipHop }),
aTrack({ artist: artistSummary, album: albumSummary }), aTrack({ artist: artistSummary, album: albumSummary, genre: tripHop }),
aTrack({ artist: artistSummary, album: albumSummary }), aTrack({ artist: artistSummary, album: albumSummary, genre: tripHop }),
]; ];
beforeEach(() => { beforeEach(() => {
@@ -1191,7 +1202,9 @@ describe("Navidrome", () => {
}); });
describe("when the album has only 1 track", () => { describe("when the album has only 1 track", () => {
const album = anAlbum({ id: "album1", name: "Burnin" }); const flipFlop = asGenre("Flip-Flop")
const album = anAlbum({ id: "album1", name: "Burnin", genre: flipFlop });
const albumSummary = albumToAlbumSummary(album); const albumSummary = albumToAlbumSummary(album);
const artist = anArtist({ const artist = anArtist({
@@ -1204,7 +1217,7 @@ describe("Navidrome", () => {
image: NO_IMAGES, image: NO_IMAGES,
}; };
const tracks = [aTrack({ artist: artistSummary, album: albumSummary })]; const tracks = [aTrack({ artist: artistSummary, album: albumSummary, genre: flipFlop })];
beforeEach(() => { beforeEach(() => {
mockGET mockGET
@@ -1252,14 +1265,14 @@ describe("Navidrome", () => {
); );
}); });
it("should return the album", async () => { it("should empty array", async () => {
const result = await navidrome const result = await navidrome
.generateToken({ username, password }) .generateToken({ username, password })
.then((it) => it as AuthSuccess) .then((it) => it as AuthSuccess)
.then((it) => navidrome.login(it.authToken)) .then((it) => navidrome.login(it.authToken))
.then((it) => it.tracks(album.id)); .then((it) => it.tracks(album.id));
expect(result).toEqual(tracks); expect(result).toEqual([]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, { expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
params: { params: {
@@ -1273,7 +1286,9 @@ describe("Navidrome", () => {
}); });
describe("a single track", () => { describe("a single track", () => {
const album = anAlbum({ id: "album1", name: "Burnin" }); const pop = asGenre("Pop")
const album = anAlbum({ id: "album1", name: "Burnin", genre: pop });
const albumSummary = albumToAlbumSummary(album); const albumSummary = albumToAlbumSummary(album);
const artist = anArtist({ const artist = anArtist({
@@ -1286,7 +1301,7 @@ describe("Navidrome", () => {
image: NO_IMAGES, image: NO_IMAGES,
}; };
const track = aTrack({ artist: artistSummary, album: albumSummary }); const track = aTrack({ artist: artistSummary, album: albumSummary, genre: pop });
beforeEach(() => { beforeEach(() => {
mockGET mockGET

View File

@@ -29,6 +29,9 @@ import {
anArtist, anArtist,
anAlbum, anAlbum,
aTrack, aTrack,
POP,
ROCK,
PUNK, TRIP_HOP
} from "./builders"; } from "./builders";
import { InMemoryMusicService } from "./in_memory_music_service"; import { InMemoryMusicService } from "./in_memory_music_service";
import supersoap from "./supersoap"; import supersoap from "./supersoap";
@@ -187,7 +190,11 @@ describe("track", () => {
name: "great song", name: "great song",
duration: randomInt(1000), duration: randomInt(1000),
number: randomInt(100), number: randomInt(100),
album: anAlbum({ name: "great album", id: uuid(), genre: "some genre" }), album: anAlbum({
name: "great album",
id: uuid(),
genre: { id: "genre101", name: "some genre" },
}),
artist: anArtist({ name: "great artist", id: uuid() }), artist: anArtist({ name: "great artist", id: uuid() }),
}); });
@@ -206,8 +213,8 @@ describe("track", () => {
artist: someTrack.artist.name, artist: someTrack.artist.name,
artistId: someTrack.artist.id, artistId: someTrack.artist.id,
duration: someTrack.duration, duration: someTrack.duration,
genre: someTrack.album.genre, genre: someTrack.album.genre?.name,
// genreId genreId: someTrack.album.genre?.id,
trackNumber: someTrack.number, trackNumber: someTrack.number,
}, },
}); });
@@ -559,17 +566,20 @@ describe("api", () => {
describe("asking for a genres", () => { describe("asking for a genres", () => {
const artist1 = anArtist({ const artist1 = anArtist({
albums: [anAlbum({ genre: "Pop" }), anAlbum({ genre: "Rock" })], albums: [
anAlbum({ genre: POP }),
anAlbum({ genre: ROCK }),
],
}); });
const artist2 = anArtist({ const artist2 = anArtist({
albums: [ albums: [
anAlbum({ genre: "Trip-Hop" }), anAlbum({ genre: TRIP_HOP }),
anAlbum({ genre: "Punk" }), anAlbum({ genre: PUNK }),
anAlbum({ genre: "Pop" }), anAlbum({ genre: POP }),
], ],
}); });
const expectedGenres = ["Pop", "Punk", "Rock", "Trip-Hop"]; const expectedGenres = [POP, PUNK, ROCK, TRIP_HOP];
beforeEach(() => { beforeEach(() => {
musicService.hasArtists(artist1, artist2); musicService.hasArtists(artist1, artist2);
@@ -586,8 +596,8 @@ describe("api", () => {
getMetadataResult({ getMetadataResult({
mediaCollection: expectedGenres.map((genre) => ({ mediaCollection: expectedGenres.map((genre) => ({
itemType: "container", itemType: "container",
id: `genre:${genre}`, id: `genre:${genre.id}`,
title: genre, title: genre.name,
})), })),
index: 0, index: 0,
total: expectedGenres.length, total: expectedGenres.length,
@@ -605,10 +615,10 @@ describe("api", () => {
}); });
expect(result[0]).toEqual( expect(result[0]).toEqual(
getMetadataResult({ getMetadataResult({
mediaCollection: ["Punk", "Rock"].map((genre) => ({ mediaCollection: [PUNK, ROCK].map((genre) => ({
itemType: "container", itemType: "container",
id: `genre:${genre}`, id: `genre:${genre.id}`,
title: genre, title: genre.name,
})), })),
index: 1, index: 1,
total: expectedGenres.length, total: expectedGenres.length,