Compare commits

...

7 Commits

Author SHA1 Message Date
Simon J
a5689c3d4b Feature/move close stream (#176)
* Move stream destroy closer to where stream is retrieved

* Change BNB_SUBSONIC_URL to be of type URLBuilder to better handle URL construction rather than string concat, should addresse #169
2023-10-10 11:25:55 +11:00
dependabot[bot]
b8caf90e06 Bump semver from 5.7.1 to 5.7.2 (#165)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-10 10:59:57 +11:00
dependabot[bot]
9b01f07484 Bump get-func-name from 2.0.0 to 2.0.2 (#173)
Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2.
- [Release notes](https://github.com/chaijs/get-func-name/releases)
- [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2)

---
updated-dependencies:
- dependency-name: get-func-name
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-10 10:59:46 +11:00
Simon J
fb5f8e81ec Ensure streams and destroyed on end of /stream request to see if addressess TCP leak issue (#175) 2023-10-09 16:19:00 +11:00
Simon J
9786d9f1dd Support for fr-FR LANG (#172) 2023-09-14 16:38:56 +10:00
dhalem
a9d88bd9eb No longer fetch entities for playlists when getting the list. (#161) 2023-04-27 19:34:59 +10:00
Simon J
f6fc7ab920 Ability to disable album art for playlists (#159) 2023-04-22 10:54:38 +10:00
16 changed files with 342 additions and 227 deletions

View File

@@ -3,6 +3,7 @@ FROM node:16-bullseye
LABEL maintainer=simojenki
ENV JEST_TIMEOUT=60000
EXPOSE 4534
RUN apt-get update && \
apt-get -y upgrade && \

View File

@@ -3,6 +3,12 @@
"build": {
"dockerfile": "Dockerfile"
},
"containerEnv": {
// these env vars need to be configured appropriately for your local dev env
"BNB_DEV_SONOS_DEVICE_IP": "${localEnv:BNB_DEV_SONOS_DEVICE_IP}",
"BNB_DEV_HOST_IP": "${localEnv:BNB_DEV_HOST_IP}",
"BNB_DEV_SUBSONIC_URL": "${localEnv:BNB_DEV_SUBSONIC_URL}"
},
"remoteUser": "node",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:1": {

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
.vscode
build
ignore
.ignore
node_modules
.yarn/*
!.yarn/patches

View File

@@ -163,6 +163,7 @@ BNB_URL | http://$(hostname):4534 | URL (including path) for bonob so that sonos
BNB_SECRET | bonob | secret used for encrypting credentials
BNB_AUTH_TIMEOUT | 1h | Timeout for the sonos auth token, described in the format [ms](https://github.com/vercel/ms), ie. '5s' == 5 seconds, '11h' == 11 hours. In the case of using Navidrome this should be less than the value for ND_SESSIONTIMEOUT
BNB_LOG_LEVEL | info | Log level. One of ['debug', 'info', 'warn', 'error']
BNB_DISABLE_PLAYLIST_ART | undefined | Disables playlist art generation, ie. when there are many playlists and art generation takes too long
BNB_SERVER_LOG_REQUESTS | false | Whether or not to log http requests
BNB_SONOS_AUTO_REGISTER | false | Whether or not to try and auto-register on startup
BNB_SONOS_DEVICE_DISCOVERY | true | Enable/Disable sonos device discovery entirely. Setting this to 'false' will disable sonos device search, regardless of whether a seed host is specified.

View File

@@ -62,9 +62,9 @@
"scripts": {
"clean": "rm -Rf build node_modules",
"build": "tsc",
"dev": "BNB_LOG_LEVEL=debug BNB_DEBUG=true BNB_SCROBBLE_TRACKS=false BNB_REPORT_NOW_PLAYING=false BNB_ICON_FOREGROUND_COLOR=white BNB_ICON_BACKGROUND_COLOR=darkgrey BNB_SONOS_SERVICE_NAME=bonobDev BNB_SONOS_DEVICE_DISCOVERY=true nodemon -V ./src/app.ts",
"devr": "BNB_LOG_LEVEL=debug BNB_DEBUG=true BNB_SCROBBLE_TRACKS=false BNB_REPORT_NOW_PLAYING=false BNB_ICON_FOREGROUND_COLOR=white BNB_ICON_BACKGROUND_COLOR=darkgrey BNB_SONOS_SERVICE_NAME=bonobDev BNB_SONOS_DEVICE_DISCOVERY=true BNB_SONOS_AUTO_REGISTER=true nodemon -V ./src/app.ts",
"register-dev": "ts-node ./src/register.ts http://$(hostname):4534",
"dev": "BNB_LOG_LEVEL=debug BNB_DEBUG=true BNB_SCROBBLE_TRACKS=false BNB_REPORT_NOW_PLAYING=false BNB_SONOS_SEED_HOST=$BNB_DEV_SONOS_DEVICE_IP BNB_SONOS_SERVICE_NAME=z_bonobDev BNB_URL=\"http://${BNB_DEV_HOST_IP}:4534\" BNB_SUBSONIC_URL=\"${BNB_DEV_SUBSONIC_URL}\" nodemon -V ./src/app.ts",
"devr": "BNB_DISABLE_PLAYLIST_ART=true BNB_LOG_LEVEL=debug BNB_DEBUG=true BNB_SCROBBLE_TRACKS=false BNB_REPORT_NOW_PLAYING=false BNB_ICON_FOREGROUND_COLOR=white BNB_ICON_BACKGROUND_COLOR=darkgrey BNB_SONOS_SEED_HOST=$BNB_DEV_SONOS_DEVICE_IP BNB_SONOS_SERVICE_NAME=z_bonobDev BNB_SONOS_DEVICE_DISCOVERY=true BNB_SONOS_AUTO_REGISTER=true BNB_URL=\"http://${BNB_DEV_HOST_IP}:4534\" BNB_SUBSONIC_URL=\"${BNB_DEV_SUBSONIC_URL}\" nodemon -V ./src/app.ts",
"register-dev": "ts-node ./src/register.ts http://${BNB_DEV_HOST_IP}:4534",
"test": "jest",
"gitinfo": "git describe --tags > .gitinfo"
},

View File

@@ -98,7 +98,7 @@ export default function () {
sid: bnbEnvVar<number>("SONOS_SERVICE_ID", { default: 246, parser: asInt }),
},
subsonic: {
url: bnbEnvVar("SUBSONIC_URL", { legacy: ["BONOB_NAVIDROME_URL"], default: `http://${hostname()}:4533` })!,
url: url(bnbEnvVar("SUBSONIC_URL", { legacy: ["BONOB_NAVIDROME_URL"], default: `http://${hostname()}:4533` })!),
customClientsFor: bnbEnvVar<string>("SUBSONIC_CUSTOM_CLIENTS", { legacy: ["BONOB_NAVIDROME_CUSTOM_CLIENTS"] }),
artistImageCache: bnbEnvVar<string>("SUBSONIC_ARTIST_IMAGE_CACHE"),
},

View File

@@ -4,7 +4,7 @@ import { option as O } from "fp-ts";
import _ from "underscore";
export type LANG = "en-US" | "da-DK" | "de-DE" | "es-ES" | "fr-FR" | "it-IT" | "ja-JP" | "nb-NO" | "nl-NL" | "pt-BR" | "sv-SE" | "zh-CN"
export type SUPPORTED_LANG = "en-US" | "da-DK" | "nl-NL";
export type SUPPORTED_LANG = "en-US" | "da-DK" | "fr-FR" | "nl-NL";
export type KEY =
| "AppLinkMessage"
| "artists"
@@ -129,6 +129,47 @@ const translations: Record<SUPPORTED_LANG, Record<KEY, string>> = {
LOVE: "Synes godt om",
LOVE_SUCCESS: "Syntes godt om"
},
"fr-FR": {
AppLinkMessage: "Associer Sonos à $BNB_SONOS_SERVICE_NAME",
artists: "Artistes",
albums: "Albums",
tracks: "Pistes",
playlists: "Playlists",
genres: "Genres",
random: "Aléatoire",
topRated: "Les mieux notés",
recentlyAdded: "Récemment ajouté",
recentlyPlayed: "Récemment joué",
mostPlayed: "Les plus joué",
success: "Succès",
failure: "Échec",
expectedConfig: "Configuration attendue",
existingServiceConfig: "La configuration de service existe",
noExistingServiceRegistration: "Aucun enregistrement de service existant",
register: "Inscription",
removeRegistration: "Supprimer l'inscription",
devices: "Appareils",
services: "Services",
login: "Se connecter",
logInToBonob: "Se connecter à $BNB_SONOS_SERVICE_NAME",
username: "Nom d'utilisateur",
password: "Mot de passe",
successfullyRegistered: "Connecté avec succès",
registrationFailed: "Échec de la connexion !",
successfullyRemovedRegistration: "Inscription supprimée avec succès",
failedToRemoveRegistration: "Échec de la suppression de l'inscription !",
invalidLinkCode: "Code non valide !",
loginSuccessful: "Connexion réussie !",
loginFailed: "La connexion a échoué !",
noSonosDevices: "Aucun appareil Sonos",
favourites: "Favoris",
STAR: "Suivre",
UNSTAR: "Ne plus suivre",
STAR_SUCCESS: "Piste suivie",
UNSTAR_SUCCESS: "Piste non suivie",
LOVE: "Aimer",
LOVE_SUCCESS: "Pistes aimée"
},
"nl-NL": {
AppLinkMessage: "Sonos koppelen aan $BNB_SONOS_SERVICE_NAME",
artists: "Artiesten",

View File

@@ -307,13 +307,13 @@ function server(
return `<Match propname="rating" value="${value}">
<Ratings>
<Rating Id="${ratingAsInt(
nextLove
)}" AutoSkip="NEVER" OnSuccessStringId="LOVE_SUCCESS" StringId="LOVE">
nextLove
)}" AutoSkip="NEVER" OnSuccessStringId="LOVE_SUCCESS" StringId="LOVE">
<Icon Controller="universal" LastModified="${LastModified}" Uri="${loveRatingIcon}" />
</Rating>
<Rating Id="${-ratingAsInt(
nextStar
)}" AutoSkip="NEVER" OnSuccessStringId="STAR_SUCCESS" StringId="STAR">
nextStar
)}" AutoSkip="NEVER" OnSuccessStringId="STAR_SUCCESS" StringId="STAR">
<Icon Controller="universal" LastModified="${LastModified}" Uri="${starsRatingIcon}" />
</Rating>
</Ratings>
@@ -327,9 +327,9 @@ function server(
<Match>
<imageSizeMap>
${SONOS_RECOMMENDED_IMAGE_SIZES.map(
(size) =>
`<sizeEntry size="${size}" substitution="/size/${size}"/>`
).join("")}
(size) =>
`<sizeEntry size="${size}" substitution="/size/${size}"/>`
).join("")}
</imageSizeMap>
</Match>
</PresentationMap>
@@ -338,9 +338,9 @@ function server(
<browseIconSizeMap>
<sizeEntry size="0" substitution="/size/legacy"/>
${SONOS_RECOMMENDED_IMAGE_SIZES.map(
(size) =>
`<sizeEntry size="${size}" substitution="/size/${size}"/>`
).join("")}
(size) =>
`<sizeEntry size="${size}" substitution="/size/${size}"/>`
).join("")}
</browseIconSizeMap>
</Match>
</PresentationMap>
@@ -406,13 +406,17 @@ function server(
trackId: id,
range: req.headers["range"] || undefined,
})
.then((stream) => {
res.on('close', () => {
stream.stream.destroy()
});
return stream;
})
.then((stream) => ({ musicLibrary: it, stream }))
)
.then(({ musicLibrary, stream }) => {
logger.debug(
`${trace} bnb<- stream response from music service for ${id}, status=${
stream.status
}, headers=(${JSON.stringify(stream.headers)})`
`${trace} bnb<- stream response from music service for ${id}, status=${stream.status}, headers=(${JSON.stringify(stream.headers)})`
);
const sonosisfyContentType = (contentType: string) =>
@@ -436,9 +440,7 @@ function server(
nowPlaying: boolean;
}) => {
logger.debug(
`${trace} bnb-> ${
req.path
}, status=${status}, headers=${JSON.stringify(headers)}`
`${trace} bnb-> ${req.path}, status=${status}, headers=${JSON.stringify(headers)}`
);
(nowPlaying
? musicLibrary.nowPlaying(id)
@@ -450,8 +452,8 @@ function server(
.forEach(([header, value]) => {
res.setHeader(header, value!);
});
if (sendStream) stream.stream.pipe(filter).pipe(res);
else res.send();
if (sendStream) stream.stream.pipe(filter).pipe(res)
else res.send()
});
};
@@ -513,15 +515,15 @@ function server(
const spec =
size == "legacy"
? {
mimeType: "image/png",
responseFormatter: (svg: string): Promise<Buffer | string> =>
sharp(Buffer.from(svg)).resize(80).png().toBuffer(),
}
mimeType: "image/png",
responseFormatter: (svg: string): Promise<Buffer | string> =>
sharp(Buffer.from(svg)).resize(80).png().toBuffer(),
}
: {
mimeType: "image/svg+xml",
responseFormatter: (svg: string): Promise<Buffer | string> =>
Promise.resolve(svg),
};
mimeType: "image/svg+xml",
responseFormatter: (svg: string): Promise<Buffer | string> =>
Promise.resolve(svg),
};
return Promise.resolve(
icon

View File

@@ -266,6 +266,9 @@ export const playlistAlbumArtURL = (
bonobUrl: URLBuilder,
playlist: Playlist
) => {
// todo: this should be put into config, or even just removed for the ND music source
if(process.env["BNB_DISABLE_PLAYLIST_ART"]) return iconArtURI(bonobUrl, "music");
const burns: BUrn[] = uniq(
playlist.entries.filter((it) => it.coverArt != undefined),
(it) => it.album.id
@@ -868,8 +871,13 @@ function bindSmapiSoapServiceToExpress(
.playlists()
.then((it) =>
Promise.all(
it.map((playlist) =>
musicLibrary.playlist(playlist.id)
it.map((playlist) => {
return {
id: playlist.id,
name: playlist.name,
entries: []
};
}
)
)
)

View File

@@ -32,6 +32,7 @@ import { b64Encode, b64Decode } from "./b64";
import logger from "./logger";
import { assertSystem, BUrn } from "./burn";
import { artist } from "./smapi";
import { URLBuilder } from "./url_builder";
export const BROWSER_HEADERS = {
accept:
@@ -344,28 +345,28 @@ export type ImageFetcher = (url: string) => Promise<CoverArt | undefined>;
export const cachingImageFetcher =
(cacheDir: string, delegate: ImageFetcher) =>
async (url: string): Promise<CoverArt | undefined> => {
const filename = path.join(cacheDir, `${Md5.hashStr(url)}.png`);
return fse
.readFile(filename)
.then((data) => ({ contentType: "image/png", data }))
.catch(() =>
delegate(url).then((image) => {
if (image) {
return sharp(image.data)
.png()
.toBuffer()
.then((png) => {
return fse
.writeFile(filename, png)
.then(() => ({ contentType: "image/png", data: png }));
});
} else {
return undefined;
}
})
);
};
async (url: string): Promise<CoverArt | undefined> => {
const filename = path.join(cacheDir, `${Md5.hashStr(url)}.png`);
return fse
.readFile(filename)
.then((data) => ({ contentType: "image/png", data }))
.catch(() =>
delegate(url).then((image) => {
if (image) {
return sharp(image.data)
.png()
.toBuffer()
.then((png) => {
return fse
.writeFile(filename, png)
.then(() => ({ contentType: "image/png", data: png }));
});
} else {
return undefined;
}
})
);
};
export const axiosImageFetcher = (url: string): Promise<CoverArt | undefined> =>
axios
@@ -412,12 +413,12 @@ interface SubsonicMusicLibrary extends MusicLibrary {
}
export class Subsonic implements MusicService {
url: string;
url: URLBuilder;
streamClientApplication: StreamClientApplication;
externalImageFetcher: ImageFetcher;
constructor(
url: string,
url: URLBuilder,
streamClientApplication: StreamClientApplication = DEFAULT,
externalImageFetcher: ImageFetcher = axiosImageFetcher
) {
@@ -433,7 +434,7 @@ export class Subsonic implements MusicService {
config: AxiosRequestConfig | undefined = {}
) =>
axios
.get(`${this.url}${path}`, {
.get(this.url.append({ pathname: path }).href(), {
params: asURLSearchParams({
u: username,
v: "1.16.1",

View File

@@ -374,23 +374,31 @@ describe("config", () => {
"BONOB_NAVIDROME_URL",
])("%s", (k) => {
describe(`when ${k} is not specified`, () => {
it(`should default to http://${hostname()}:4533`, () => {
expect(config().subsonic.url).toEqual(`http://${hostname()}:4533`);
it(`should default to http://${hostname()}:4533/`, () => {
expect(config().subsonic.url.href()).toEqual(`http://${hostname()}:4533/`);
});
});
describe(`when ${k} is ''`, () => {
it(`should default to http://${hostname()}:4533`, () => {
it(`should default to http://${hostname()}:4533/`, () => {
process.env[k] = "";
expect(config().subsonic.url).toEqual(`http://${hostname()}:4533`);
expect(config().subsonic.url.href()).toEqual(`http://${hostname()}:4533/`);
});
});
describe(`when ${k} is specified`, () => {
it(`should use it for ${k}`, () => {
const url = "http://navidrome.example.com:1234";
const url = "http://navidrome.example.com:1234/some-context-path";
process.env[k] = url;
expect(config().subsonic.url).toEqual(url);
expect(config().subsonic.url.href()).toEqual(url);
});
});
describe(`when ${k} is specified with trailing slash`, () => {
it(`should maintain the trailing slash as URLBuilder will remove it when required ${k}`, () => {
const url = "http://navidrome.example.com:1234/";
process.env[k] = url;
expect(config().subsonic.url.href()).toEqual(url);
});
});
});

View File

@@ -34,7 +34,7 @@ describe("i8n", () => {
describe("langs", () => {
it("should be all langs that are explicitly defined", () => {
expect(langs()).toEqual(["en-US", "da-DK", "nl-NL"]);
expect(langs()).toEqual(["en-US", "da-DK", "fr-FR", "nl-NL"]);
});
});

View File

@@ -755,15 +755,22 @@ describe("server", () => {
const trackId = `t-${uuid()}`;
const smapiAuthToken: SmapiToken = { token: `token-${uuid()}`, key: `key-${uuid()}` };
const streamContent = (content: string) => ({
pipe: (_: Transform) => {
return {
pipe: (res: Response) => {
res.send(content);
},
};
},
});
const streamContent = (content: string) => {
const self = {
destroyed: false,
pipe: (_: Transform) => {
return {
pipe: (res: Response) => {
res.send(content);
}
};
},
destroy: () => {
self.destroyed = true;
}
};
return self;
};
describe("HEAD requests", () => {
describe("when there is no Bearer token", () => {
@@ -829,6 +836,8 @@ describe("server", () => {
);
expect(res.headers["content-length"]).toEqual("123");
expect(res.body).toEqual({});
expect(trackStream.stream.destroyed).toBe(true);
});
});
@@ -854,6 +863,8 @@ describe("server", () => {
expect(res.status).toEqual(404);
expect(res.body).toEqual({});
expect(trackStream.stream.destroyed).toBe(true);
});
});
});
@@ -916,6 +927,8 @@ describe("server", () => {
expect(musicLibrary.nowPlaying).not.toHaveBeenCalled();
expect(musicLibrary.stream).toHaveBeenCalledWith({ trackId });
expect(stream.stream.destroyed).toBe(true);
});
});
@@ -959,6 +972,8 @@ describe("server", () => {
expect(musicService.login).toHaveBeenCalledWith(serviceToken);
expect(musicLibrary.nowPlaying).toHaveBeenCalledWith(trackId);
expect(musicLibrary.stream).toHaveBeenCalledWith({ trackId });
expect(stream.stream.destroyed).toBe(true);
});
});
@@ -1000,6 +1015,8 @@ describe("server", () => {
expect(musicService.login).toHaveBeenCalledWith(serviceToken);
expect(musicLibrary.nowPlaying).toHaveBeenCalledWith(trackId);
expect(musicLibrary.stream).toHaveBeenCalledWith({ trackId });
expect(stream.stream.destroyed).toBe(true);
});
});
@@ -1040,6 +1057,8 @@ describe("server", () => {
expect(musicService.login).toHaveBeenCalledWith(serviceToken);
expect(musicLibrary.nowPlaying).toHaveBeenCalledWith(trackId);
expect(musicLibrary.stream).toHaveBeenCalledWith({ trackId });
expect(stream.stream.destroyed).toBe(true);
});
});
@@ -1083,6 +1102,8 @@ describe("server", () => {
expect(musicService.login).toHaveBeenCalledWith(serviceToken);
expect(musicLibrary.nowPlaying).toHaveBeenCalledWith(trackId);
expect(musicLibrary.stream).toHaveBeenCalledWith({ trackId });
expect(stream.stream.destroyed).toBe(true);
});
});
});
@@ -1131,6 +1152,8 @@ describe("server", () => {
trackId,
range: requestedRange,
});
expect(stream.stream.destroyed).toBe(true);
});
});
@@ -1178,6 +1201,8 @@ describe("server", () => {
trackId,
range: "4000-5000",
});
expect(stream.stream.destroyed).toBe(true);
});
});
});

View File

@@ -135,8 +135,8 @@ describe("service config", () => {
"Sonos koppelen aan music land"
);
// no fr-FR translation, so use en-US
expect(sonosString("AppLinkMessage", "fr-FR")).toEqual(
// no pt-BR translation, so use en-US
expect(sonosString("AppLinkMessage", "pt-BR")).toEqual(
"Linking sonos with music land"
);
});
@@ -519,30 +519,30 @@ describe("playlistAlbumArtURL", () => {
});
describe("when the playlist has external ids", () => {
const bonobUrl = url("http://localhost:1234/context-path?search=yes");
const externalArt1 = {
system: "external",
resource: "http://example.com/image1.jpg",
};
const externalArt2 = {
system: "external",
resource: "http://example.com/image2.jpg",
};
const playlist = aPlaylist({
entries: [
aTrack({
coverArt: externalArt1,
album: anAlbumSummary({ id: "album1" }),
}),
aTrack({
coverArt: externalArt2,
album: anAlbumSummary({ id: "album2" }),
}),
],
});
it("should format the url with encrypted urn", () => {
const bonobUrl = url("http://localhost:1234/context-path?search=yes");
const externalArt1 = {
system: "external",
resource: "http://example.com/image1.jpg",
};
const externalArt2 = {
system: "external",
resource: "http://example.com/image2.jpg",
};
const playlist = aPlaylist({
entries: [
aTrack({
coverArt: externalArt1,
album: anAlbumSummary({ id: "album1" }),
}),
aTrack({
coverArt: externalArt2,
album: anAlbumSummary({ id: "album2" }),
}),
],
});
expect(playlistAlbumArtURL(bonobUrl, playlist).href()).toEqual(
`http://localhost:1234/context-path/art/${encodeURIComponent(
formatForURL(externalArt1)
@@ -550,6 +550,26 @@ describe("playlistAlbumArtURL", () => {
formatForURL(externalArt2)
)}/size/180?search=yes`
);
});
describe("when BNB_NO_PLAYLIST_ART is set", () => {
const OLD_ENV = process.env;
beforeEach(() => {
process.env = { ...OLD_ENV };
process.env["BNB_DISABLE_PLAYLIST_ART"] = "true";
});
afterEach(() => {
process.env = OLD_ENV;
});
it("should return an icon", () => {
expect(playlistAlbumArtURL(bonobUrl, playlist).href()).toEqual(
`http://localhost:1234/context-path/icon/music/size/legacy?search=yes`
);
});
});
});
@@ -1651,10 +1671,10 @@ describe("wsdl api", () => {
});
describe("asking for playlists", () => {
const playlist1 = aPlaylist({ id: "1", name: "pl1" });
const playlist2 = aPlaylist({ id: "2", name: "pl2" });
const playlist3 = aPlaylist({ id: "3", name: "pl3" });
const playlist4 = aPlaylist({ id: "4", name: "pl4" });
const playlist1 = aPlaylist({ id: "1", name: "pl1", entries: []});
const playlist2 = aPlaylist({ id: "2", name: "pl2", entries: []});
const playlist3 = aPlaylist({ id: "3", name: "pl3", entries: []});
const playlist4 = aPlaylist({ id: "4", name: "pl4", entries: []});
const playlists = [playlist1, playlist2, playlist3, playlist4];

View File

@@ -62,6 +62,7 @@ import {
} from "./builders";
import { b64Encode } from "../src/b64";
import { BUrn } from "../src/burn";
import { URLBuilder } from "../src/url_builder";
describe("t", () => {
it("should be an md5 of the password and the salt", () => {
@@ -688,7 +689,7 @@ describe("asTrack", () => {
});
describe("Subsonic", () => {
const url = "http://127.0.0.22:4567";
const url = new URLBuilder("http://127.0.0.22:4567/some-context-path");
const username = `user1-${uuid()}`;
const password = `pass1-${uuid()}`;
const salt = "saltysalty";
@@ -756,7 +757,7 @@ describe("Subsonic", () => {
expect(parseToken(token.serviceToken)).toEqual({ username, password, type: PING_OK["subsonic-response"].type })
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/ping.view`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/ping.view' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -777,7 +778,7 @@ describe("Subsonic", () => {
expect(parseToken(token.serviceToken)).toEqual({ username, password, type })
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/ping.view`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/ping.view' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -802,11 +803,11 @@ describe("Subsonic", () => {
expect(parseToken(token.serviceToken)).toEqual({ username, password, type: "navidrome", bearer: navidromeToken })
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/ping.view`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/ping.view' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.post).toHaveBeenCalledWith(`${url}/auth/login`, {
expect(axios.post).toHaveBeenCalledWith(url.append({ pathname: '/auth/login' }).href(), {
username,
password,
});
@@ -848,7 +849,7 @@ describe("Subsonic", () => {
expect(parseToken(refreshedToken.serviceToken)).toEqual({ username, password, type })
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/ping.view`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/ping.view' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -876,11 +877,11 @@ describe("Subsonic", () => {
expect(parseToken(refreshedToken.serviceToken)).toEqual({ username, password, type: "navidrome", bearer: navidromeToken })
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/ping.view`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/ping.view' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.post).toHaveBeenCalledWith(`${url}/auth/login`, {
expect(axios.post).toHaveBeenCalledWith(url.append({ pathname: '/auth/login' }).href(), {
username,
password,
});
@@ -941,7 +942,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getGenres' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -968,7 +969,7 @@ describe("Subsonic", () => {
expect(result).toEqual([{ id: b64Encode("genre1"), name: "genre1" }]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getGenres' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -1003,7 +1004,7 @@ describe("Subsonic", () => {
{ id: b64Encode("g4"), name: "g4" },
]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getGenres`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getGenres' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -1059,7 +1060,7 @@ describe("Subsonic", () => {
similarArtists: artist.similarArtists,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1067,7 +1068,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1118,7 +1119,7 @@ describe("Subsonic", () => {
similarArtists: artist.similarArtists,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1126,7 +1127,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1171,7 +1172,7 @@ describe("Subsonic", () => {
similarArtists: artist.similarArtists,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1179,7 +1180,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1225,7 +1226,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1233,7 +1234,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1276,7 +1277,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1284,7 +1285,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1327,7 +1328,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1335,7 +1336,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1379,7 +1380,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1387,7 +1388,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1432,7 +1433,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1440,7 +1441,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1483,7 +1484,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1491,7 +1492,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1532,7 +1533,7 @@ describe("Subsonic", () => {
similarArtists: [],
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtist`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1540,7 +1541,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtistInfo2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtistInfo2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: artist.id,
@@ -1661,7 +1662,7 @@ describe("Subsonic", () => {
total: 1,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -1702,7 +1703,7 @@ describe("Subsonic", () => {
total: 4,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -1730,7 +1731,7 @@ describe("Subsonic", () => {
expect(artists).toEqual({ results: expectedResults, total: 4 });
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -1786,12 +1787,12 @@ describe("Subsonic", () => {
total: 2,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "byGenre",
@@ -1838,12 +1839,12 @@ describe("Subsonic", () => {
total: 3,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "newest",
@@ -1889,12 +1890,12 @@ describe("Subsonic", () => {
total: 2,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "recent",
@@ -1931,12 +1932,12 @@ describe("Subsonic", () => {
total: 1,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "frequent",
@@ -1973,12 +1974,12 @@ describe("Subsonic", () => {
total: 1,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "highest",
@@ -2024,12 +2025,12 @@ describe("Subsonic", () => {
total: 1,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "alphabeticalByArtist",
@@ -2074,12 +2075,12 @@ describe("Subsonic", () => {
total: 0,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "alphabeticalByArtist",
@@ -2139,12 +2140,12 @@ describe("Subsonic", () => {
total: 6,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "alphabeticalByArtist",
@@ -2190,12 +2191,12 @@ describe("Subsonic", () => {
total: 6,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbumList2`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbumList2' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
type: "alphabeticalByArtist",
@@ -2263,13 +2264,13 @@ describe("Subsonic", () => {
total: 4,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2320,13 +2321,13 @@ describe("Subsonic", () => {
total: 4,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2376,13 +2377,13 @@ describe("Subsonic", () => {
total: 4,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2442,13 +2443,13 @@ describe("Subsonic", () => {
total: 5,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2506,13 +2507,13 @@ describe("Subsonic", () => {
total: 5,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2568,13 +2569,13 @@ describe("Subsonic", () => {
total: 5,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getArtists`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getArtists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getAlbumList2`,
url.append({ pathname: '/rest/getAlbumList2' }).href(),
{
params: asURLSearchParams({
...authParamsPlusJson,
@@ -2620,7 +2621,7 @@ describe("Subsonic", () => {
expect(result).toEqual(album);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -2698,7 +2699,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1, track2, track3, track4]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -2745,7 +2746,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -2780,7 +2781,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -2831,7 +2832,7 @@ describe("Subsonic", () => {
rating: { love: true, stars: 4 },
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getSong`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getSong' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: track.id,
@@ -2839,7 +2840,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -2878,7 +2879,7 @@ describe("Subsonic", () => {
rating: { love: false, stars: 0 },
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getSong`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getSong' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: track.id,
@@ -2886,7 +2887,7 @@ describe("Subsonic", () => {
headers,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getAlbum`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getAlbum' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: album.id,
@@ -3033,7 +3034,7 @@ describe("Subsonic", () => {
});
expect(result.stream).toEqual(stream);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/stream`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/stream' }).href(), {
params: asURLSearchParams({
...authParams,
id: trackId,
@@ -3139,7 +3140,7 @@ describe("Subsonic", () => {
});
expect(result.stream).toEqual(stream);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/stream`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/stream' }).href(), {
params: asURLSearchParams({
...authParams,
id: trackId,
@@ -3182,7 +3183,7 @@ describe("Subsonic", () => {
.then((it) => it.stream({ trackId, range: undefined }));
expect(streamClientApplication).toHaveBeenCalledWith(track);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/stream`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/stream' }).href(), {
params: asURLSearchParams({
...authParams,
id: trackId,
@@ -3224,7 +3225,7 @@ describe("Subsonic", () => {
.then((it) => it.stream({ trackId, range }));
expect(streamClientApplication).toHaveBeenCalledWith(track);
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/stream`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/stream' }).href(), {
params: asURLSearchParams({
...authParams,
id: trackId,
@@ -3267,7 +3268,7 @@ describe("Subsonic", () => {
data: streamResponse.data,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getCoverArt`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getCoverArt' }).href(), {
params: asURLSearchParams({
...authParams,
id: coverArtId,
@@ -3303,7 +3304,7 @@ describe("Subsonic", () => {
data: streamResponse.data,
});
expect(axios.get).toHaveBeenCalledWith(`${url}/rest/getCoverArt`, {
expect(axios.get).toHaveBeenCalledWith(url.append({ pathname: '/rest/getCoverArt' }).href(), {
params: asURLSearchParams({
...authParams,
id: coverArtId,
@@ -3429,7 +3430,7 @@ describe("Subsonic", () => {
});
expect(axios.get).toHaveBeenCalledWith(
`${url}/rest/getCoverArt`,
url.append({ pathname: '/rest/getCoverArt' }).href(),
{
params: asURLSearchParams({
...authParams,
@@ -3495,7 +3496,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/star`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/star' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: trackId,
@@ -3528,7 +3529,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/unstar`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/unstar' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: trackId,
@@ -3587,7 +3588,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/setRating`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/setRating' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: trackId,
@@ -3648,14 +3649,14 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/unstar`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/unstar' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: trackId,
}),
headers,
});
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/setRating`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/setRating' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: trackId,
@@ -3715,7 +3716,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/scrobble`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/scrobble' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -3744,7 +3745,7 @@ describe("Subsonic", () => {
expect(result).toEqual(false);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/scrobble`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/scrobble' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -3770,7 +3771,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/scrobble`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/scrobble' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -3799,7 +3800,7 @@ describe("Subsonic", () => {
expect(result).toEqual(false);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/scrobble`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/scrobble' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -3827,7 +3828,7 @@ describe("Subsonic", () => {
expect(result).toEqual([artistToArtistSummary(artist1)]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 20,
@@ -3861,7 +3862,7 @@ describe("Subsonic", () => {
artistToArtistSummary(artist2),
]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 20,
@@ -3887,7 +3888,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 20,
@@ -3923,7 +3924,7 @@ describe("Subsonic", () => {
expect(result).toEqual([albumToAlbumSummary(album)]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -3973,7 +3974,7 @@ describe("Subsonic", () => {
albumToAlbumSummary(album2),
]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -3999,7 +4000,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -4045,7 +4046,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -4117,7 +4118,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1, track2]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -4143,7 +4144,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/search3`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/search3' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
artistCount: 0,
@@ -4174,7 +4175,7 @@ describe("Subsonic", () => {
expect(result).toEqual([playlist]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylists`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -4199,7 +4200,7 @@ describe("Subsonic", () => {
expect(result).toEqual(playlists);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylists`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -4219,7 +4220,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylists`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylists' }).href(), {
params: asURLSearchParams(authParamsPlusJson),
headers,
});
@@ -4304,7 +4305,7 @@ describe("Subsonic", () => {
],
});
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -4331,7 +4332,7 @@ describe("Subsonic", () => {
expect(result).toEqual(playlist);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id: playlist.id,
@@ -4359,7 +4360,7 @@ describe("Subsonic", () => {
expect(result).toEqual({ id, name });
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/createPlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/createPlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
f: "json",
@@ -4383,7 +4384,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/deletePlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/deletePlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
id,
@@ -4408,7 +4409,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/updatePlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/updatePlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
playlistId,
@@ -4433,7 +4434,7 @@ describe("Subsonic", () => {
expect(result).toEqual(true);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/updatePlaylist`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/updatePlaylist' }).href(), {
params: asURLSearchParams({
...authParamsPlusJson,
playlistId,
@@ -4480,7 +4481,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs2`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getSimilarSongs2' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",
@@ -4550,7 +4551,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1, track2, track3]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs2`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getSimilarSongs2' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",
@@ -4577,7 +4578,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getSimilarSongs2`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getSimilarSongs2' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",
@@ -4644,7 +4645,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getTopSongs' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",
@@ -4711,7 +4712,7 @@ describe("Subsonic", () => {
expect(result).toEqual([track1, track2, track3]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getTopSongs' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",
@@ -4751,7 +4752,7 @@ describe("Subsonic", () => {
expect(result).toEqual([]);
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getTopSongs`, {
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getTopSongs' }).href(), {
params: asURLSearchParams({
...authParams,
f: "json",

View File

@@ -2072,9 +2072,9 @@ get-caller-file@^2.0.5:
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-func-name@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
version "2.0.2"
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
get-intrinsic@^1.0.2:
version "1.2.0"
@@ -3829,21 +3829,21 @@ sax@>=0.6:
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
semver@7.x, semver@^7.3.5, semver@^7.3.8:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@~7.0.0:
version "7.0.0"