mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Ability to see TopRated/starred albums (#63)
This commit is contained in:
18
src/i8n.ts
18
src/i8n.ts
@@ -81,10 +81,10 @@ const translations: Record<SUPPORTED_LANG, Record<KEY, string>> = {
|
|||||||
loginFailed: "Login failed!",
|
loginFailed: "Login failed!",
|
||||||
noSonosDevices: "No sonos devices",
|
noSonosDevices: "No sonos devices",
|
||||||
favourites: "Favourites",
|
favourites: "Favourites",
|
||||||
STAR: "Star track",
|
STAR: "Star",
|
||||||
UNSTAR: "Un-star track",
|
UNSTAR: "Un-star",
|
||||||
STAR_SUCCESS: "Track starred successfully",
|
STAR_SUCCESS: "Track starred",
|
||||||
UNSTAR_SUCCESS: "Track un-starred successfully",
|
UNSTAR_SUCCESS: "Track un-starred",
|
||||||
LOVE: "Love",
|
LOVE: "Love",
|
||||||
LOVE_SUCCESS: "Track loved"
|
LOVE_SUCCESS: "Track loved"
|
||||||
},
|
},
|
||||||
@@ -122,11 +122,11 @@ const translations: Record<SUPPORTED_LANG, Record<KEY, string>> = {
|
|||||||
loginFailed: "Inloggen mislukt!",
|
loginFailed: "Inloggen mislukt!",
|
||||||
noSonosDevices: "Geen Sonos-apparaten",
|
noSonosDevices: "Geen Sonos-apparaten",
|
||||||
favourites: "Favorieten",
|
favourites: "Favorieten",
|
||||||
STAR: "Ster spoor",
|
STAR: "Ster ",
|
||||||
UNSTAR: "Track zonder ster",
|
UNSTAR: "Een ster",
|
||||||
STAR_SUCCESS: "Track succesvol gemarkeerd",
|
STAR_SUCCESS: "Nummer met ster",
|
||||||
UNSTAR_SUCCESS: "Succes zonder ster bijhouden",
|
UNSTAR_SUCCESS: "Track zonder ster",
|
||||||
LOVE: "Liefde ",
|
LOVE: "Liefde",
|
||||||
LOVE_SUCCESS: "Volg geliefd"
|
LOVE_SUCCESS: "Volg geliefd"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export const asResult = <T>([results, total]: [T[], number]) => ({
|
|||||||
|
|
||||||
export type ArtistQuery = Paging;
|
export type ArtistQuery = Paging;
|
||||||
|
|
||||||
export type AlbumQueryType = 'alphabeticalByArtist' | 'alphabeticalByName' | 'byGenre' | 'random' | 'recent' | 'frequent' | 'newest' | 'starred';
|
export type AlbumQueryType = 'alphabeticalByArtist' | 'alphabeticalByName' | 'byGenre' | 'random' | 'recentlyPlayed' | 'mostPlayed' | 'recentlyAdded' | 'favourited' | 'starred';
|
||||||
|
|
||||||
export type AlbumQuery = Paging & {
|
export type AlbumQuery = Paging & {
|
||||||
type: AlbumQueryType;
|
type: AlbumQueryType;
|
||||||
|
|||||||
40
src/smapi.ts
40
src/smapi.ts
@@ -81,10 +81,11 @@ export type GetDeviceAuthTokenResult = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ratingAsInt = (rating: Rating): number => rating.stars * 10 + (rating.love ? 1 : 0) + 100;
|
export const ratingAsInt = (rating: Rating): number =>
|
||||||
|
rating.stars * 10 + (rating.love ? 1 : 0) + 100;
|
||||||
export const ratingFromInt = (value: number): Rating => {
|
export const ratingFromInt = (value: number): Rating => {
|
||||||
const x = value - 100;
|
const x = value - 100;
|
||||||
return { love: (x % 10 == 1), stars: Math.floor(x / 10) }
|
return { love: x % 10 == 1, stars: Math.floor(x / 10) };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MediaCollection = {
|
export type MediaCollection = {
|
||||||
@@ -309,7 +310,7 @@ export const track = (bonobUrl: URLBuilder, track: Track) => ({
|
|||||||
},
|
},
|
||||||
dynamic: {
|
dynamic: {
|
||||||
property: [{ name: "rating", value: `${ratingAsInt(track.rating)}` }],
|
property: [{ name: "rating", value: `${ratingAsInt(track.rating)}` }],
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const artist = (bonobUrl: URLBuilder, artist: ArtistSummary) => ({
|
export const artist = (bonobUrl: URLBuilder, artist: ArtistSummary) => ({
|
||||||
@@ -426,10 +427,7 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
.then(splitId(id))
|
.then(splitId(id))
|
||||||
.then(async ({ musicLibrary, accessToken, typeId }) =>
|
.then(async ({ musicLibrary, accessToken, typeId }) =>
|
||||||
musicLibrary.track(typeId!).then((it) => ({
|
musicLibrary.track(typeId!).then((it) => ({
|
||||||
getMediaMetadataResult: track(
|
getMediaMetadataResult: track(urlWithToken(accessToken), it),
|
||||||
urlWithToken(accessToken),
|
|
||||||
it
|
|
||||||
),
|
|
||||||
}))
|
}))
|
||||||
),
|
),
|
||||||
search: async (
|
search: async (
|
||||||
@@ -516,10 +514,7 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
case "track":
|
case "track":
|
||||||
return musicLibrary.track(typeId).then((it) => ({
|
return musicLibrary.track(typeId).then((it) => ({
|
||||||
getExtendedMetadataResult: {
|
getExtendedMetadataResult: {
|
||||||
mediaMetadata: track(
|
mediaMetadata: track(urlWithToken(accessToken), it),
|
||||||
urlWithToken(accessToken),
|
|
||||||
it
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
case "album":
|
case "album":
|
||||||
@@ -606,12 +601,12 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
||||||
itemType: "albumList",
|
itemType: "albumList",
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// id: "topRatedAlbums",
|
id: "starredAlbums",
|
||||||
// title: lang("topRated"),
|
title: lang("topRated"),
|
||||||
// albumArtURI: iconArtURI(bonobUrl, "star").href(),
|
albumArtURI: iconArtURI(bonobUrl, "star").href(),
|
||||||
// itemType: "albumList",
|
itemType: "albumList",
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
id: "playlists",
|
id: "playlists",
|
||||||
title: lang("playlists"),
|
title: lang("playlists"),
|
||||||
@@ -710,23 +705,28 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
...paging,
|
...paging,
|
||||||
});
|
});
|
||||||
case "favouriteAlbums":
|
case "favouriteAlbums":
|
||||||
|
return albums({
|
||||||
|
type: "favourited",
|
||||||
|
...paging,
|
||||||
|
});
|
||||||
|
case "starredAlbums":
|
||||||
return albums({
|
return albums({
|
||||||
type: "starred",
|
type: "starred",
|
||||||
...paging,
|
...paging,
|
||||||
});
|
});
|
||||||
case "recentlyAdded":
|
case "recentlyAdded":
|
||||||
return albums({
|
return albums({
|
||||||
type: "newest",
|
type: "recentlyAdded",
|
||||||
...paging,
|
...paging,
|
||||||
});
|
});
|
||||||
case "recentlyPlayed":
|
case "recentlyPlayed":
|
||||||
return albums({
|
return albums({
|
||||||
type: "recent",
|
type: "recentlyPlayed",
|
||||||
...paging,
|
...paging,
|
||||||
});
|
});
|
||||||
case "mostPlayed":
|
case "mostPlayed":
|
||||||
return albums({
|
return albums({
|
||||||
type: "frequent",
|
type: "mostPlayed",
|
||||||
...paging,
|
...paging,
|
||||||
});
|
});
|
||||||
case "genres":
|
case "genres":
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Track,
|
Track,
|
||||||
CoverArt,
|
CoverArt,
|
||||||
Rating,
|
Rating,
|
||||||
|
AlbumQueryType,
|
||||||
} from "./music_service";
|
} from "./music_service";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
@@ -204,6 +205,7 @@ export type GetSongResponse = {
|
|||||||
export type GetStarredResponse = {
|
export type GetStarredResponse = {
|
||||||
starred2: {
|
starred2: {
|
||||||
song: song[];
|
song: song[];
|
||||||
|
album: album[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,11 +263,14 @@ export const asTrack = (album: Album, song: song): Track => ({
|
|||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
love: song.starred != undefined,
|
love: song.starred != undefined,
|
||||||
stars: (song.userRating && song.userRating <= 5 && song.userRating >= 0 ? song.userRating : 0),
|
stars:
|
||||||
|
song.userRating && song.userRating <= 5 && song.userRating >= 0
|
||||||
|
? song.userRating
|
||||||
|
: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const asAlbum = (album: album) => ({
|
const asAlbum = (album: album): Album => ({
|
||||||
id: album.id,
|
id: album.id,
|
||||||
name: album.name,
|
name: album.name,
|
||||||
year: album.year,
|
year: album.year,
|
||||||
@@ -350,6 +355,18 @@ export const axiosImageFetcher = (url: string): Promise<CoverArt | undefined> =>
|
|||||||
}))
|
}))
|
||||||
.catch(() => undefined);
|
.catch(() => undefined);
|
||||||
|
|
||||||
|
const AlbumQueryTypeToSubsonicType: Record<AlbumQueryType, string> = {
|
||||||
|
alphabeticalByArtist: "alphabeticalByArtist",
|
||||||
|
alphabeticalByName: "alphabeticalByName",
|
||||||
|
byGenre: "byGenre",
|
||||||
|
random: "random",
|
||||||
|
recentlyPlayed: "recent",
|
||||||
|
mostPlayed: "frequent",
|
||||||
|
recentlyAdded: "newest",
|
||||||
|
favourited: "starred",
|
||||||
|
starred: "highest",
|
||||||
|
};
|
||||||
|
|
||||||
export class Subsonic implements MusicService {
|
export class Subsonic implements MusicService {
|
||||||
url: string;
|
url: string;
|
||||||
encryption: Encryption;
|
encryption: Encryption;
|
||||||
@@ -536,6 +553,31 @@ export class Subsonic implements MusicService {
|
|||||||
songs: it.searchResult3.song || [],
|
songs: it.searchResult3.song || [],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
getAlbumList2 = (credentials: Credentials, q: AlbumQuery) =>
|
||||||
|
Promise.all([
|
||||||
|
this.getArtists(credentials).then((it) =>
|
||||||
|
_.inject(it, (total, artist) => total + artist.albumCount, 0)
|
||||||
|
),
|
||||||
|
this.getJSON<GetAlbumListResponse>(credentials, "/rest/getAlbumList2", {
|
||||||
|
type: AlbumQueryTypeToSubsonicType[q.type],
|
||||||
|
...(q.genre ? { genre: b64Decode(q.genre) } : {}),
|
||||||
|
size: 500,
|
||||||
|
offset: q._index,
|
||||||
|
})
|
||||||
|
.then((response) => response.albumList2.album || [])
|
||||||
|
.then(this.toAlbumSummary),
|
||||||
|
]).then(([total, albums]) => ({
|
||||||
|
results: albums.slice(0, q._count),
|
||||||
|
total: albums.length == 500 ? total : q._index + albums.length,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// getStarred2 = (credentials: Credentials): Promise<{ albums: Album[] }> =>
|
||||||
|
// this.getJSON<GetStarredResponse>(credentials, "/rest/getStarred2")
|
||||||
|
// .then((it) => it.starred2)
|
||||||
|
// .then((it) => ({
|
||||||
|
// albums: it.album.map(asAlbum),
|
||||||
|
// }));
|
||||||
|
|
||||||
async login(token: string) {
|
async login(token: string) {
|
||||||
const subsonic = this;
|
const subsonic = this;
|
||||||
const credentials: Credentials = this.parseToken(token);
|
const credentials: Credentials = this.parseToken(token);
|
||||||
@@ -552,25 +594,7 @@ export class Subsonic implements MusicService {
|
|||||||
artist: async (id: string): Promise<Artist> =>
|
artist: async (id: string): Promise<Artist> =>
|
||||||
subsonic.getArtistWithInfo(credentials, id),
|
subsonic.getArtistWithInfo(credentials, id),
|
||||||
albums: async (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
albums: async (q: AlbumQuery): Promise<Result<AlbumSummary>> =>
|
||||||
Promise.all([
|
subsonic.getAlbumList2(credentials, q),
|
||||||
subsonic
|
|
||||||
.getArtists(credentials)
|
|
||||||
.then((it) =>
|
|
||||||
_.inject(it, (total, artist) => total + artist.albumCount, 0)
|
|
||||||
),
|
|
||||||
subsonic
|
|
||||||
.getJSON<GetAlbumListResponse>(credentials, "/rest/getAlbumList2", {
|
|
||||||
type: q.type,
|
|
||||||
...(q.genre ? { genre: b64Decode(q.genre) } : {}),
|
|
||||||
size: 500,
|
|
||||||
offset: q._index,
|
|
||||||
})
|
|
||||||
.then((response) => response.albumList2.album || [])
|
|
||||||
.then(subsonic.toAlbumSummary),
|
|
||||||
]).then(([total, albums]) => ({
|
|
||||||
results: albums.slice(0, q._count),
|
|
||||||
total: albums.length == 500 ? total : q._index + albums.length,
|
|
||||||
})),
|
|
||||||
album: (id: string): Promise<Album> => subsonic.getAlbum(credentials, id),
|
album: (id: string): Promise<Album> => subsonic.getAlbum(credentials, id),
|
||||||
genres: () =>
|
genres: () =>
|
||||||
subsonic
|
subsonic
|
||||||
|
|||||||
@@ -977,6 +977,12 @@ describe("api", () => {
|
|||||||
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
||||||
itemType: "albumList",
|
itemType: "albumList",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "starredAlbums",
|
||||||
|
title: "Top Rated",
|
||||||
|
albumArtURI: iconArtURI(bonobUrl, "star").href(),
|
||||||
|
itemType: "albumList",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "playlists",
|
id: "playlists",
|
||||||
title: "Playlists",
|
title: "Playlists",
|
||||||
@@ -1064,6 +1070,12 @@ describe("api", () => {
|
|||||||
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
albumArtURI: iconArtURI(bonobUrl, "heart").href(),
|
||||||
itemType: "albumList",
|
itemType: "albumList",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "starredAlbums",
|
||||||
|
title: "Best beoordeeld",
|
||||||
|
albumArtURI: iconArtURI(bonobUrl, "star").href(),
|
||||||
|
itemType: "albumList",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "playlists",
|
id: "playlists",
|
||||||
title: "Afspeellijsten",
|
title: "Afspeellijsten",
|
||||||
@@ -1705,6 +1717,54 @@ describe("api", () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
||||||
|
type: "favourited",
|
||||||
|
_index: paging.index,
|
||||||
|
_count: paging.count,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("asking for starred albums", () => {
|
||||||
|
const albums = [rock2, rock1, pop2];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
musicLibrary.albums.mockResolvedValue({
|
||||||
|
results: albums,
|
||||||
|
total: allAlbums.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return some", async () => {
|
||||||
|
const paging = {
|
||||||
|
index: 0,
|
||||||
|
count: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await ws.getMetadataAsync({
|
||||||
|
id: "starredAlbums",
|
||||||
|
...paging,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result[0]).toEqual(
|
||||||
|
getMetadataResult({
|
||||||
|
mediaCollection: albums.map((it) => ({
|
||||||
|
itemType: "album",
|
||||||
|
id: `album:${it.id}`,
|
||||||
|
title: it.name,
|
||||||
|
albumArtURI: defaultAlbumArtURI(
|
||||||
|
bonobUrlWithAccessToken,
|
||||||
|
it
|
||||||
|
).href(),
|
||||||
|
canPlay: true,
|
||||||
|
artistId: `artist:${it.artistId}`,
|
||||||
|
artist: it.artistName,
|
||||||
|
})),
|
||||||
|
index: 0,
|
||||||
|
total: 6,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
||||||
type: "starred",
|
type: "starred",
|
||||||
_index: paging.index,
|
_index: paging.index,
|
||||||
@@ -1754,7 +1814,7 @@ describe("api", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
||||||
type: "recent",
|
type: "recentlyPlayed",
|
||||||
_index: paging.index,
|
_index: paging.index,
|
||||||
_count: paging.count,
|
_count: paging.count,
|
||||||
});
|
});
|
||||||
@@ -1802,7 +1862,7 @@ describe("api", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
||||||
type: "frequent",
|
type: "mostPlayed",
|
||||||
_index: paging.index,
|
_index: paging.index,
|
||||||
_count: paging.count,
|
_count: paging.count,
|
||||||
});
|
});
|
||||||
@@ -1850,7 +1910,7 @@ describe("api", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
expect(musicLibrary.albums).toHaveBeenCalledWith({
|
||||||
type: "newest",
|
type: "recentlyAdded",
|
||||||
_index: paging.index,
|
_index: paging.index,
|
||||||
_count: paging.count,
|
_count: paging.count,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ const maybeIdFromCoverArtId = (coverArt: string | undefined) =>
|
|||||||
coverArt ? splitCoverArtId(coverArt)[1] : "";
|
coverArt ? splitCoverArtId(coverArt)[1] : "";
|
||||||
|
|
||||||
const asAlbumJson = (
|
const asAlbumJson = (
|
||||||
artist: Artist,
|
artist: { id: string | undefined, name: string | undefined },
|
||||||
album: AlbumSummary,
|
album: AlbumSummary,
|
||||||
tracks: Track[] = []
|
tracks: Track[] = []
|
||||||
) => ({
|
) => ({
|
||||||
@@ -353,9 +353,9 @@ const getAlbumJson = (artist: Artist, album: Album, tracks: Track[]) =>
|
|||||||
|
|
||||||
const getSongJson = (track: Track) => subsonicOK({ song: asSongJson(track) });
|
const getSongJson = (track: Track) => subsonicOK({ song: asSongJson(track) });
|
||||||
|
|
||||||
// const getStarredJson = ({ songIds }: { songIds: string[] }) => subsonicOK({starred2: {
|
// const getStarredJson = ({ albums }: { albums: Album[] }) => subsonicOK({starred2: {
|
||||||
// album: [],
|
// album: albums.map(it => asAlbumJson({ id: it.artistId, name: it.artistName }, it, [])),
|
||||||
// song: songIds.map((id) => ({ id })),
|
// song: [],
|
||||||
// }})
|
// }})
|
||||||
|
|
||||||
const subsonicOK = (body: any = {}) => ({
|
const subsonicOK = (body: any = {}) => ({
|
||||||
@@ -1389,11 +1389,13 @@ describe("Subsonic", () => {
|
|||||||
|
|
||||||
describe("getting albums", () => {
|
describe("getting albums", () => {
|
||||||
describe("filtering", () => {
|
describe("filtering", () => {
|
||||||
const album1 = anAlbum({ genre: asGenre("Pop") });
|
const album1 = anAlbum({ id: "album1", genre: asGenre("Pop") });
|
||||||
const album2 = anAlbum({ genre: asGenre("Rock") });
|
const album2 = anAlbum({ id: "album2", genre: asGenre("Rock") });
|
||||||
const album3 = anAlbum({ genre: asGenre("Pop") });
|
const album3 = anAlbum({ id: "album3", genre: asGenre("Pop") });
|
||||||
|
const album4 = anAlbum({ id: "album4", genre: asGenre("Pop") });
|
||||||
|
const album5 = anAlbum({ id: "album5", genre: asGenre("Pop") });
|
||||||
|
|
||||||
const artist = anArtist({ albums: [album1, album2, album3] });
|
const artist = anArtist({ albums: [album1, album2, album3, album4, album5] });
|
||||||
|
|
||||||
describe("by genre", () => {
|
describe("by genre", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -1472,7 +1474,7 @@ describe("Subsonic", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should pass the filter to navidrome", async () => {
|
it("should pass the filter to navidrome", async () => {
|
||||||
const q: AlbumQuery = { _index: 0, _count: 100, type: "newest" };
|
const q: AlbumQuery = { _index: 0, _count: 100, type: "recentlyAdded" };
|
||||||
const result = await navidrome
|
const result = await navidrome
|
||||||
.generateToken({ username, password })
|
.generateToken({ username, password })
|
||||||
.then((it) => it as AuthSuccess)
|
.then((it) => it as AuthSuccess)
|
||||||
@@ -1522,7 +1524,7 @@ describe("Subsonic", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should pass the filter to navidrome", async () => {
|
it("should pass the filter to navidrome", async () => {
|
||||||
const q: AlbumQuery = { _index: 0, _count: 100, type: "recent" };
|
const q: AlbumQuery = { _index: 0, _count: 100, type: "recentlyPlayed" };
|
||||||
const result = await navidrome
|
const result = await navidrome
|
||||||
.generateToken({ username, password })
|
.generateToken({ username, password })
|
||||||
.then((it) => it as AuthSuccess)
|
.then((it) => it as AuthSuccess)
|
||||||
@@ -1567,7 +1569,7 @@ describe("Subsonic", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should pass the filter to navidrome", async () => {
|
it("should pass the filter to navidrome", async () => {
|
||||||
const q: AlbumQuery = { _index: 0, _count: 100, type: "frequent" };
|
const q: AlbumQuery = { _index: 0, _count: 100, type: "mostPlayed" };
|
||||||
const result = await navidrome
|
const result = await navidrome
|
||||||
.generateToken({ username, password })
|
.generateToken({ username, password })
|
||||||
.then((it) => it as AuthSuccess)
|
.then((it) => it as AuthSuccess)
|
||||||
@@ -1595,6 +1597,51 @@ describe("Subsonic", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("by starred", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockGET
|
||||||
|
.mockImplementationOnce(() => Promise.resolve(ok(PING_OK)))
|
||||||
|
.mockImplementationOnce(() =>
|
||||||
|
Promise.resolve(ok(asArtistsJson([artist])))
|
||||||
|
)
|
||||||
|
.mockImplementationOnce(
|
||||||
|
() =>
|
||||||
|
// album1 never played
|
||||||
|
Promise.resolve(ok(getAlbumListJson([[artist, album2]])))
|
||||||
|
// album3 never played
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should pass the filter to navidrome", async () => {
|
||||||
|
const q: AlbumQuery = { _index: 0, _count: 100, type: "starred" };
|
||||||
|
const result = await navidrome
|
||||||
|
.generateToken({ username, password })
|
||||||
|
.then((it) => it as AuthSuccess)
|
||||||
|
.then((it) => navidrome.login(it.authToken))
|
||||||
|
.then((it) => it.albums(q));
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
results: [album2].map(albumToAlbumSummary),
|
||||||
|
total: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
|
||||||
|
params: asURLSearchParams(authParamsPlusJson),
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
|
||||||
|
params: asURLSearchParams({
|
||||||
|
...authParamsPlusJson,
|
||||||
|
type: "highest",
|
||||||
|
size: 500,
|
||||||
|
offset: 0,
|
||||||
|
}),
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when the artist has only 1 album", () => {
|
describe("when the artist has only 1 album", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user