mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Remove tracks function, replace with just getting album
This commit is contained in:
@@ -175,8 +175,7 @@ export interface MusicLibrary {
|
|||||||
artists(q: ArtistQuery): Promise<Result<ArtistSummary>>;
|
artists(q: ArtistQuery): Promise<Result<ArtistSummary>>;
|
||||||
artist(id: string): Promise<Artist>;
|
artist(id: string): Promise<Artist>;
|
||||||
albums(q: AlbumQuery): Promise<Result<AlbumSummary>>;
|
albums(q: AlbumQuery): Promise<Result<AlbumSummary>>;
|
||||||
album(id: string): Promise<AlbumSummary>;
|
album(id: string): Promise<Album>;
|
||||||
tracks(albumId: string): Promise<Track[]>;
|
|
||||||
track(trackId: string): Promise<Track>;
|
track(trackId: string): Promise<Track>;
|
||||||
genres(): Promise<Genre[]>;
|
genres(): Promise<Genre[]>;
|
||||||
years(): Promise<Year[]>;
|
years(): Promise<Year[]>;
|
||||||
|
|||||||
@@ -981,7 +981,8 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
});
|
});
|
||||||
case "album":
|
case "album":
|
||||||
return musicLibrary
|
return musicLibrary
|
||||||
.tracks(typeId!)
|
.album(typeId!)
|
||||||
|
.then(it => it.tracks)
|
||||||
.then(slice2(paging))
|
.then(slice2(paging))
|
||||||
.then(([page, total]) => {
|
.then(([page, total]) => {
|
||||||
return getMetadataResult({
|
return getMetadataResult({
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
AlbumQuery,
|
AlbumQuery,
|
||||||
ArtistQuery,
|
ArtistQuery,
|
||||||
MusicLibrary,
|
MusicLibrary,
|
||||||
|
Album,
|
||||||
AlbumSummary,
|
AlbumSummary,
|
||||||
Rating,
|
Rating,
|
||||||
Artist,
|
Artist,
|
||||||
@@ -19,9 +20,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
Subsonic,
|
Subsonic,
|
||||||
CustomPlayers,
|
CustomPlayers,
|
||||||
GetAlbumResponse,
|
|
||||||
asTrack,
|
asTrack,
|
||||||
asAlbumSummary,
|
|
||||||
PingResponse,
|
PingResponse,
|
||||||
NO_CUSTOM_PLAYERS,
|
NO_CUSTOM_PLAYERS,
|
||||||
asToken,
|
asToken,
|
||||||
@@ -171,25 +170,11 @@ export class SubsonicMusicLibrary implements MusicLibrary {
|
|||||||
albums = async (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
albums = async (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
||||||
this.subsonic.getAlbumList2(this.credentials, q);
|
this.subsonic.getAlbumList2(this.credentials, q);
|
||||||
|
|
||||||
// todo: this should probably return an Album
|
album = (id: string): Promise<Album> =>
|
||||||
album = (id: string): Promise<AlbumSummary> =>
|
this.subsonic.getAlbum(this.credentials, id);
|
||||||
this.subsonic.getAlbum(this.credentials, id).then(albumToAlbumSummary);
|
|
||||||
|
|
||||||
genres = () => this.subsonic.getGenres(this.credentials);
|
genres = () => this.subsonic.getGenres(this.credentials);
|
||||||
|
|
||||||
// todo: do we even need this if Album has tracks?
|
|
||||||
tracks = (albumId: string) =>
|
|
||||||
this.subsonic
|
|
||||||
.getJSON<GetAlbumResponse>(this.credentials, "/rest/getAlbum", {
|
|
||||||
id: albumId,
|
|
||||||
})
|
|
||||||
.then((it) => it.album)
|
|
||||||
.then((album) =>
|
|
||||||
(album.song || []).map((song) =>
|
|
||||||
asTrack(asAlbumSummary(album), song, this.customPlayers)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
track = (trackId: string) =>
|
track = (trackId: string) =>
|
||||||
this.subsonic.getTrack(this.credentials, trackId);
|
this.subsonic.getTrack(this.credentials, trackId);
|
||||||
|
|
||||||
|
|||||||
@@ -167,23 +167,6 @@ describe("InMemoryMusicService", () => {
|
|||||||
service.hasTracks(track1, track2, track3, track4);
|
service.hasTracks(track1, track2, track3, track4);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("fetching tracks for an album", () => {
|
|
||||||
it("should return only tracks on that album", async () => {
|
|
||||||
expect(await musicLibrary.tracks(artist1Album1.id)).toEqual([
|
|
||||||
{ ...track1, rating: { love: false, stars: 0 } },
|
|
||||||
{ ...track2, rating: { love: false, stars: 0 } },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("fetching tracks for an album that doesnt exist", () => {
|
|
||||||
it("should return empty array", async () => {
|
|
||||||
expect(await musicLibrary.tracks("non existant album id")).toEqual(
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("fetching a single track", () => {
|
describe("fetching a single track", () => {
|
||||||
describe("when it exists", () => {
|
describe("when it exists", () => {
|
||||||
it("should return the track", async () => {
|
it("should return the track", async () => {
|
||||||
@@ -424,7 +407,10 @@ describe("InMemoryMusicService", () => {
|
|||||||
describe("when it exists", () => {
|
describe("when it exists", () => {
|
||||||
it("should provide an album", async () => {
|
it("should provide an album", async () => {
|
||||||
expect(await musicLibrary.album(artist1_album5.id)).toEqual(
|
expect(await musicLibrary.album(artist1_album5.id)).toEqual(
|
||||||
artist1_album5
|
{
|
||||||
|
...artist1_album5,
|
||||||
|
tracks: []
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export class InMemoryMusicService implements MusicService {
|
|||||||
pipe(
|
pipe(
|
||||||
this.artists.flatMap((it) => it.albums).find((it) => it.id === id),
|
this.artists.flatMap((it) => it.albums).find((it) => it.id === id),
|
||||||
O.fromNullable,
|
O.fromNullable,
|
||||||
O.map((it) => Promise.resolve(it)),
|
O.map((it) => Promise.resolve({ ...it, tracks: [] })),
|
||||||
O.getOrElse(() => Promise.reject(`No album with id '${id}'`))
|
O.getOrElse(() => Promise.reject(`No album with id '${id}'`))
|
||||||
),
|
),
|
||||||
genres: () =>
|
genres: () =>
|
||||||
@@ -117,12 +117,6 @@ export class InMemoryMusicService implements MusicService {
|
|||||||
A.sort(fromCompare<Genre>((x, y) => ordString.compare(x.id, y.id)))
|
A.sort(fromCompare<Genre>((x, y) => ordString.compare(x.id, y.id)))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
tracks: (albumId: string) =>
|
|
||||||
Promise.resolve(
|
|
||||||
this.tracks
|
|
||||||
.filter((it) => it.album.id === albumId)
|
|
||||||
.map((it) => ({ ...it, rating: { love: false, stars: 0 } }))
|
|
||||||
),
|
|
||||||
rate: (_: string, _2: Rating) => Promise.resolve(false),
|
rate: (_: string, _2: Rating) => Promise.resolve(false),
|
||||||
track: (trackId: string) =>
|
track: (trackId: string) =>
|
||||||
pipe(
|
pipe(
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ import {
|
|||||||
PUNK,
|
PUNK,
|
||||||
aPlaylist,
|
aPlaylist,
|
||||||
aRadioStation,
|
aRadioStation,
|
||||||
|
anArtistSummary,
|
||||||
|
anAlbumSummary,
|
||||||
} 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";
|
||||||
@@ -2356,10 +2358,8 @@ describe("wsdl api", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("asking for an album", () => {
|
describe("asking for an album", () => {
|
||||||
const album = anAlbum();
|
const album = anAlbumSummary();
|
||||||
const artist = anArtist({
|
const artist = anArtistSummary();
|
||||||
albums: [album],
|
|
||||||
});
|
|
||||||
|
|
||||||
const track1 = aTrack({ artist, album, number: 1 });
|
const track1 = aTrack({ artist, album, number: 1 });
|
||||||
const track2 = aTrack({ artist, album, number: 2 });
|
const track2 = aTrack({ artist, album, number: 2 });
|
||||||
@@ -2370,7 +2370,12 @@ describe("wsdl api", () => {
|
|||||||
const tracks = [track1, track2, track3, track4, track5];
|
const tracks = [track1, track2, track3, track4, track5];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
musicLibrary.tracks.mockResolvedValue(tracks);
|
musicLibrary.album.mockResolvedValue(anAlbum({
|
||||||
|
...album,
|
||||||
|
artistName: artist.name,
|
||||||
|
artistId: artist.id,
|
||||||
|
tracks
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("asking for all for an album", () => {
|
describe("asking for all for an album", () => {
|
||||||
@@ -2394,7 +2399,7 @@ describe("wsdl api", () => {
|
|||||||
total: tracks.length,
|
total: tracks.length,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(musicLibrary.tracks).toHaveBeenCalledWith(album.id);
|
expect(musicLibrary.album).toHaveBeenCalledWith(album.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2421,7 +2426,7 @@ describe("wsdl api", () => {
|
|||||||
total: tracks.length,
|
total: tracks.length,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(musicLibrary.tracks).toHaveBeenCalledWith(album.id);
|
expect(musicLibrary.album).toHaveBeenCalledWith(album.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ import {
|
|||||||
TranscodingCustomPlayers,
|
TranscodingCustomPlayers,
|
||||||
CustomPlayers,
|
CustomPlayers,
|
||||||
NO_CUSTOM_PLAYERS,
|
NO_CUSTOM_PLAYERS,
|
||||||
Subsonic
|
Subsonic,
|
||||||
|
asGenre
|
||||||
} from "../src/subsonic";
|
} from "../src/subsonic";
|
||||||
|
|
||||||
import { b64Encode } from "../src/b64";
|
import { b64Encode } from "../src/b64";
|
||||||
@@ -779,54 +780,232 @@ describe("subsonic", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("getting an album", () => {
|
describe("getting an album", () => {
|
||||||
beforeEach(() => {
|
describe("when there are no custom players", () => {
|
||||||
customPlayers.encodingFor.mockReturnValue(O.none);
|
beforeEach(() => {
|
||||||
|
customPlayers.encodingFor.mockReturnValue(O.none);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the album has some tracks", () => {
|
||||||
|
const artistId = "artist6677"
|
||||||
|
const artistName = "Fizzy Wizzy"
|
||||||
|
|
||||||
|
const albumSummary = anAlbumSummary({ artistId, artistName })
|
||||||
|
const artistSumamry = anArtistSummary({ id: artistId, name: artistName })
|
||||||
|
|
||||||
|
// todo: fix these ratings
|
||||||
|
const tracks = [
|
||||||
|
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
||||||
|
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
||||||
|
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
||||||
|
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
||||||
|
];
|
||||||
|
|
||||||
|
const album = anAlbum({
|
||||||
|
...albumSummary,
|
||||||
|
tracks,
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockGET.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(getAlbumJson(album)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the album", async () => {
|
||||||
|
const result = await subsonic.getAlbum(credentials, album.id);
|
||||||
|
|
||||||
|
expect(result).toEqual(album);
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(
|
||||||
|
url.append({ pathname: "/rest/getAlbum" }).href(),
|
||||||
|
{
|
||||||
|
params: asURLSearchParams({
|
||||||
|
...authParamsPlusJson,
|
||||||
|
id: album.id,
|
||||||
|
}),
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the album has no tracks", () => {
|
||||||
|
const artistId = "artist6677"
|
||||||
|
const artistName = "Fizzy Wizzy"
|
||||||
|
|
||||||
|
const albumSummary = anAlbumSummary({ artistId, artistName })
|
||||||
|
|
||||||
|
const album = anAlbum({
|
||||||
|
...albumSummary,
|
||||||
|
tracks: [],
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockGET.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(getAlbumJson(album)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the album", async () => {
|
||||||
|
const result = await subsonic.getAlbum(credentials, album.id);
|
||||||
|
|
||||||
|
expect(result).toEqual(album);
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(
|
||||||
|
url.append({ pathname: "/rest/getAlbum" }).href(),
|
||||||
|
{
|
||||||
|
params: asURLSearchParams({
|
||||||
|
...authParamsPlusJson,
|
||||||
|
id: album.id,
|
||||||
|
}),
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when it exists", () => {
|
describe("when a custom player is configured for the mime type", () => {
|
||||||
const artistId = "artist6677"
|
const hipHop = asGenre("Hip-Hop");
|
||||||
const artistName = "Fizzy Wizzy"
|
const tripHop = asGenre("Trip-Hop");
|
||||||
|
|
||||||
const albumSummary = anAlbumSummary({ artistId, artistName })
|
const albumSummary = anAlbumSummary({ id: "album1", name: "Burnin", genre: hipHop });
|
||||||
const artistSumamry = anArtistSummary({ id: artistId, name: artistName })
|
|
||||||
|
|
||||||
// todo: fix these ratings
|
const artistSummary = anArtistSummary({
|
||||||
const tracks = [
|
id: "artist1",
|
||||||
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
name: "Bob Marley"
|
||||||
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
});
|
||||||
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
|
||||||
aTrack({ artist: artistSumamry, album: albumSummary, rating: { love: false, stars: 0 } }),
|
|
||||||
];
|
|
||||||
|
|
||||||
const album = anAlbum({
|
const alac = aTrack({
|
||||||
...albumSummary,
|
artist: artistSummary,
|
||||||
tracks,
|
album: albumSummary,
|
||||||
artistId,
|
encoding: {
|
||||||
artistName,
|
player: "bonob",
|
||||||
});
|
mimeType: "audio/alac",
|
||||||
|
},
|
||||||
|
genre: hipHop,
|
||||||
|
rating: {
|
||||||
|
love: true,
|
||||||
|
stars: 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const m4a = aTrack({
|
||||||
|
artist: artistSummary,
|
||||||
|
album: albumSummary,
|
||||||
|
encoding: {
|
||||||
|
player: "bonob",
|
||||||
|
mimeType: "audio/m4a",
|
||||||
|
},
|
||||||
|
genre: hipHop,
|
||||||
|
rating: {
|
||||||
|
love: false,
|
||||||
|
stars: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const mp3 = aTrack({
|
||||||
|
artist: artistSummary,
|
||||||
|
album: albumSummary,
|
||||||
|
encoding: {
|
||||||
|
player: "bonob",
|
||||||
|
mimeType: "audio/mp3",
|
||||||
|
},
|
||||||
|
genre: tripHop,
|
||||||
|
rating: {
|
||||||
|
love: true,
|
||||||
|
stars: 5,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
const album = anAlbum({
|
||||||
mockGET.mockImplementationOnce(() =>
|
...albumSummary,
|
||||||
Promise.resolve(ok(getAlbumJson(album)))
|
tracks: [alac, m4a, mp3]
|
||||||
);
|
})
|
||||||
});
|
|
||||||
|
beforeEach(() => {
|
||||||
|
customPlayers.encodingFor
|
||||||
|
.mockReturnValueOnce(
|
||||||
|
O.of({ player: "bonob+audio/alac", mimeType: "audio/flac" })
|
||||||
|
)
|
||||||
|
.mockReturnValueOnce(
|
||||||
|
O.of({ player: "bonob+audio/m4a", mimeType: "audio/opus" })
|
||||||
|
)
|
||||||
|
.mockReturnValueOnce(O.none);
|
||||||
|
|
||||||
it("should return the album", async () => {
|
mockGET.mockImplementationOnce(() =>
|
||||||
const result = await subsonic.getAlbum(credentials, album.id);
|
Promise.resolve(ok(getAlbumJson(album)))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual(album);
|
it("should return the album with custom players applied", async () => {
|
||||||
|
const result = await subsonic.getAlbum(credentials, album.id);
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(
|
expect(result).toEqual({
|
||||||
url.append({ pathname: "/rest/getAlbum" }).href(),
|
...album,
|
||||||
{
|
tracks: [
|
||||||
params: asURLSearchParams({
|
{
|
||||||
...authParamsPlusJson,
|
...alac,
|
||||||
id: album.id,
|
encoding: {
|
||||||
}),
|
player: "bonob+audio/alac",
|
||||||
headers,
|
mimeType: "audio/flac",
|
||||||
}
|
},
|
||||||
);
|
// todo: this doesnt seem right? why dont the ratings come back?
|
||||||
});
|
rating: {
|
||||||
|
love: false,
|
||||||
|
stars: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...m4a,
|
||||||
|
encoding: {
|
||||||
|
player: "bonob+audio/m4a",
|
||||||
|
mimeType: "audio/opus",
|
||||||
|
},
|
||||||
|
rating: {
|
||||||
|
love: false,
|
||||||
|
stars: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...mp3,
|
||||||
|
encoding: {
|
||||||
|
player: "bonob",
|
||||||
|
mimeType: "audio/mp3",
|
||||||
|
},
|
||||||
|
rating: {
|
||||||
|
love: false,
|
||||||
|
stars: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(
|
||||||
|
url.append({ pathname: "/rest/getAlbum" }).href(),
|
||||||
|
{
|
||||||
|
params: asURLSearchParams({
|
||||||
|
...authParamsPlusJson,
|
||||||
|
id: album.id,
|
||||||
|
}),
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(customPlayers.encodingFor).toHaveBeenCalledTimes(3);
|
||||||
|
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(1, {
|
||||||
|
mimeType: "audio/alac",
|
||||||
|
});
|
||||||
|
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(2, {
|
||||||
|
mimeType: "audio/m4a",
|
||||||
|
});
|
||||||
|
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(3, {
|
||||||
|
mimeType: "audio/mp3",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ import {
|
|||||||
ROCK,
|
ROCK,
|
||||||
aRadioStation,
|
aRadioStation,
|
||||||
anAlbumSummary,
|
anAlbumSummary,
|
||||||
anArtistSummary
|
|
||||||
} from "./builders";
|
} from "./builders";
|
||||||
import { b64Encode } from "../src/b64";
|
import { b64Encode } from "../src/b64";
|
||||||
import { BUrn } from "../src/burn";
|
import { BUrn } from "../src/burn";
|
||||||
@@ -2592,332 +2591,7 @@ describe("SubsonicMusicLibrary", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("getting tracks", () => {
|
describe("getting tracks", () => {
|
||||||
describe("for an album", () => {
|
|
||||||
describe("when there are no custom players", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
customPlayers.encodingFor.mockReturnValue(O.none);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the album has multiple tracks, some of which are rated", () => {
|
|
||||||
const hipHop = asGenre("Hip-Hop");
|
|
||||||
const tripHop = asGenre("Trip-Hop");
|
|
||||||
|
|
||||||
const albumSummary = anAlbumSummary({
|
|
||||||
id: "album1",
|
|
||||||
name: "Burnin",
|
|
||||||
genre: hipHop,
|
|
||||||
});
|
|
||||||
|
|
||||||
const artistSummary = anArtistSummary({
|
|
||||||
id: "artist1",
|
|
||||||
name: "Bob Marley"
|
|
||||||
});
|
|
||||||
|
|
||||||
const track1 = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
genre: hipHop,
|
|
||||||
rating: {
|
|
||||||
love: true,
|
|
||||||
stars: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const track2 = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
genre: hipHop,
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const track3 = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
genre: tripHop,
|
|
||||||
rating: {
|
|
||||||
love: true,
|
|
||||||
stars: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const track4 = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
genre: tripHop,
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const album = anAlbum({
|
|
||||||
...albumSummary,
|
|
||||||
tracks: [track1, track2, track3, track4]
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(getAlbumJson(album)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the album", async () => {
|
|
||||||
const result = await subsonic.tracks(album.id);
|
|
||||||
|
|
||||||
// todo: not this
|
|
||||||
const blatRating = (t: Track) => ({
|
|
||||||
...t,
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(result).toEqual([
|
|
||||||
blatRating(track1),
|
|
||||||
blatRating(track2),
|
|
||||||
blatRating(track3),
|
|
||||||
blatRating(track4),
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(
|
|
||||||
url.append({ pathname: "/rest/getAlbum" }).href(),
|
|
||||||
{
|
|
||||||
params: asURLSearchParams({
|
|
||||||
...authParamsPlusJson,
|
|
||||||
id: album.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the album has only 1 track", () => {
|
|
||||||
// todo: why do i care about the genre in here?
|
|
||||||
const flipFlop = asGenre("Flip-Flop");
|
|
||||||
|
|
||||||
const albumSummary = anAlbumSummary({
|
|
||||||
id: "album1",
|
|
||||||
name: "Burnin",
|
|
||||||
genre: flipFlop,
|
|
||||||
});
|
|
||||||
|
|
||||||
const artistSummary = anArtistSummary({
|
|
||||||
id: "artist1",
|
|
||||||
name: "Bob Marley"
|
|
||||||
});
|
|
||||||
|
|
||||||
const track = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
genre: flipFlop,
|
|
||||||
});
|
|
||||||
|
|
||||||
const album = anAlbum({
|
|
||||||
...albumSummary,
|
|
||||||
tracks: [track]
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(getAlbumJson(album)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the album", async () => {
|
|
||||||
const result = await subsonic.tracks(album.id);
|
|
||||||
|
|
||||||
expect(result).toEqual([{
|
|
||||||
...track,
|
|
||||||
// todo: not sure about this
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(
|
|
||||||
url.append({ pathname: "/rest/getAlbum" }).href(),
|
|
||||||
{
|
|
||||||
params: asURLSearchParams({
|
|
||||||
...authParamsPlusJson,
|
|
||||||
id: album.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when the album has no tracks", () => {
|
|
||||||
const album = anAlbum({
|
|
||||||
tracks: []
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockGET.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(getAlbumJson(album)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should empty array", async () => {
|
|
||||||
const result = await subsonic.tracks(album.id);
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(
|
|
||||||
url.append({ pathname: "/rest/getAlbum" }).href(),
|
|
||||||
{
|
|
||||||
params: asURLSearchParams({
|
|
||||||
...authParamsPlusJson,
|
|
||||||
id: album.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when a custom player is configured for the mime type", () => {
|
|
||||||
const hipHop = asGenre("Hip-Hop");
|
|
||||||
const tripHop = asGenre("Trip-Hop");
|
|
||||||
|
|
||||||
const albumSummary = anAlbumSummary({ id: "album1", name: "Burnin", genre: hipHop });
|
|
||||||
|
|
||||||
const artistSummary = anArtistSummary({
|
|
||||||
id: "artist1",
|
|
||||||
name: "Bob Marley"
|
|
||||||
});
|
|
||||||
|
|
||||||
const alac = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob",
|
|
||||||
mimeType: "audio/alac",
|
|
||||||
},
|
|
||||||
genre: hipHop,
|
|
||||||
rating: {
|
|
||||||
love: true,
|
|
||||||
stars: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const m4a = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob",
|
|
||||||
mimeType: "audio/m4a",
|
|
||||||
},
|
|
||||||
genre: hipHop,
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const mp3 = aTrack({
|
|
||||||
artist: artistSummary,
|
|
||||||
album: albumSummary,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob",
|
|
||||||
mimeType: "audio/mp3",
|
|
||||||
},
|
|
||||||
genre: tripHop,
|
|
||||||
rating: {
|
|
||||||
love: true,
|
|
||||||
stars: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const album = anAlbum({
|
|
||||||
...albumSummary,
|
|
||||||
tracks: [alac, m4a, mp3]
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
customPlayers.encodingFor
|
|
||||||
.mockReturnValueOnce(
|
|
||||||
O.of({ player: "bonob+audio/alac", mimeType: "audio/flac" })
|
|
||||||
)
|
|
||||||
.mockReturnValueOnce(
|
|
||||||
O.of({ player: "bonob+audio/m4a", mimeType: "audio/opus" })
|
|
||||||
)
|
|
||||||
.mockReturnValueOnce(O.none);
|
|
||||||
|
|
||||||
mockGET.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve(ok(getAlbumJson(album)))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the album with custom players applied", async () => {
|
|
||||||
const result = await subsonic.tracks(album.id);
|
|
||||||
|
|
||||||
expect(result).toEqual([
|
|
||||||
{
|
|
||||||
...alac,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob+audio/alac",
|
|
||||||
mimeType: "audio/flac",
|
|
||||||
},
|
|
||||||
// todo: this doesnt seem right? why dont the ratings come back?
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...m4a,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob+audio/m4a",
|
|
||||||
mimeType: "audio/opus",
|
|
||||||
},
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...mp3,
|
|
||||||
encoding: {
|
|
||||||
player: "bonob",
|
|
||||||
mimeType: "audio/mp3",
|
|
||||||
},
|
|
||||||
rating: {
|
|
||||||
love: false,
|
|
||||||
stars: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(
|
|
||||||
url.append({ pathname: "/rest/getAlbum" }).href(),
|
|
||||||
{
|
|
||||||
params: asURLSearchParams({
|
|
||||||
...authParamsPlusJson,
|
|
||||||
id: album.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(customPlayers.encodingFor).toHaveBeenCalledTimes(3);
|
|
||||||
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(1, {
|
|
||||||
mimeType: "audio/alac",
|
|
||||||
});
|
|
||||||
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(2, {
|
|
||||||
mimeType: "audio/m4a",
|
|
||||||
});
|
|
||||||
expect(customPlayers.encodingFor).toHaveBeenNthCalledWith(3, {
|
|
||||||
mimeType: "audio/mp3",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("a single track", () => {
|
describe("a single track", () => {
|
||||||
const pop = asGenre("Pop");
|
const pop = asGenre("Pop");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user