mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Compare commits
11 Commits
v0.6.9
...
feature/so
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4aa72c6d85 | ||
|
|
66c248fe44 | ||
|
|
1a251400ec | ||
|
|
0c9513bec9 | ||
|
|
b7beb4c610 | ||
|
|
5ce2e4efb7 | ||
|
|
8ef9ca80b6 | ||
|
|
a5689c3d4b | ||
|
|
b8caf90e06 | ||
|
|
9b01f07484 | ||
|
|
fb5f8e81ec |
@@ -1,4 +1,4 @@
|
||||
FROM node:16-bullseye
|
||||
FROM node:20-bullseye
|
||||
|
||||
LABEL maintainer=simojenki
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
"BNB_DEV_SUBSONIC_URL": "${localEnv:BNB_DEV_SUBSONIC_URL}"
|
||||
},
|
||||
"remoteUser": "node",
|
||||
"forwardPorts": [4534],
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:1": {
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"version": "latest",
|
||||
"moby": true
|
||||
}
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -21,11 +21,11 @@ jobs:
|
||||
-
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: 20
|
||||
-
|
||||
run: yarn install
|
||||
run: npm install
|
||||
-
|
||||
run: yarn test
|
||||
run: npm test
|
||||
|
||||
|
||||
push_to_registry:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
.vscode
|
||||
build
|
||||
ignore
|
||||
.ignore
|
||||
node_modules
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
|
||||
147529
.yarn/releases/yarn-1.22.19.cjs
vendored
147529
.yarn/releases/yarn-1.22.19.cjs
vendored
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-1.22.19.cjs
|
||||
34
Dockerfile
34
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:16-bullseye-slim as build
|
||||
FROM node:20-bullseye-slim as build
|
||||
|
||||
WORKDIR /bonob
|
||||
|
||||
@@ -9,12 +9,11 @@ COPY typings ./typings
|
||||
COPY web ./web
|
||||
COPY tests ./tests
|
||||
COPY jest.config.js .
|
||||
COPY package.json .
|
||||
COPY register.js .
|
||||
COPY .npmrc .
|
||||
COPY tsconfig.json .
|
||||
COPY yarn.lock .
|
||||
COPY .yarnrc.yml .
|
||||
COPY .yarn/releases ./.yarn/releases
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
|
||||
ENV JEST_TIMEOUT=60000
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -29,24 +28,15 @@ RUN apt-get update && \
|
||||
g++ && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
yarn config set network-timeout 600000 -g && \
|
||||
yarn install \
|
||||
--prefer-offline \
|
||||
--frozen-lockfile \
|
||||
--non-interactive \
|
||||
--production=false && \
|
||||
yarn test --no-cache && \
|
||||
yarn gitinfo && \
|
||||
yarn build && \
|
||||
npm install && \
|
||||
npm test && \
|
||||
npm run gitinfo && \
|
||||
npm run build && \
|
||||
rm -Rf node_modules && \
|
||||
NODE_ENV=production yarn install \
|
||||
--prefer-offline \
|
||||
--pure-lockfile \
|
||||
--non-interactive \
|
||||
--production=true
|
||||
NODE_ENV=production npm install --omit=dev
|
||||
|
||||
|
||||
FROM node:16-bullseye-slim
|
||||
FROM node:20-bullseye-slim
|
||||
|
||||
LABEL maintainer="simojenki" \
|
||||
org.opencontainers.image.source="https://github.com/simojenki/bonob" \
|
||||
@@ -62,7 +52,7 @@ EXPOSE $BNB_PORT
|
||||
WORKDIR /bonob
|
||||
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
COPY package-lock.json .
|
||||
|
||||
COPY --from=build /bonob/build/src ./src
|
||||
COPY --from=build /bonob/node_modules ./node_modules
|
||||
@@ -75,7 +65,7 @@ RUN apt-get update && \
|
||||
apt-get -y install --no-install-recommends \
|
||||
libvips \
|
||||
tzdata \
|
||||
wget && \
|
||||
wget && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -16,7 +16,7 @@ Support for Subsonic API clones (tested against Navidrome and Gonic).
|
||||
- Search by Album, Artist, Track
|
||||
- Playlist editing through sonos app.
|
||||
- Marking of songs as favourites and with ratings through the sonos app.
|
||||
- Localization (only en-US, da-DK & nl-NL supported currently, require translations for other languages). [Sonos localization and supported languages](https://developer.sonos.com/build/content-service-add-features/strings-and-localization/)
|
||||
- Localization (only en-US, da-DK & nl-NL supported currently, require translations for other languages). [Sonos localization and supported languages](https://docs.sonos.com/docs/localization)
|
||||
- Auto discovery of sonos devices
|
||||
- Discovery of sonos devices using seed IP address
|
||||
- Auto registration with sonos on start
|
||||
@@ -218,17 +218,11 @@ Afterwards the Sonos app displays a dropdown underneath the service, allowing to
|
||||
- Implement the MusicService/MusicLibrary interface
|
||||
- Startup bonob with your new implementation.
|
||||
|
||||
## A note on transcoding
|
||||
|
||||
tldr; Transcoding to mp3/m4a is not supported as sonos devices will not play the track. However transcoding to flac does work, use BNB_SUBSONIC_CUSTOM_CLIENTS=audio/flac if you want to transcode flac->flac ie. to downsample HD flacs (see below).
|
||||
|
||||
Sonos devices are very particular about how audio streams are presented to them, see [streaming basics](https://developer.sonos.com/build/content-service-add-features/streaming-basics/). When using transcoding both Navidrome and Gonic report no 'content-length', nor do they support range queries, this will cause the sonos device to fail to play the track.
|
||||
|
||||
### Audio File type specific transcoding options within Subsonic
|
||||
|
||||
In some situations you may wish to have different 'Players' within you Subsonic server so that you can configure different transcoding options depending on the file type. For example if you have flacs with a mixture of frequency formats where not all are supported by sonos [See issue #52](https://github.com/simojenki/bonob/issues/52) & [Sonos supported audio formats](https://developer.sonos.com/build/content-service-add-features/supported-audio-formats/)
|
||||
In some situations you may wish to have different 'Players' within your Subsonic server so that you can configure different transcoding options depending on the file type. For example if you have flacs with a mixture of frequency formats where not all are supported by sonos [See issue #52](https://github.com/simojenki/bonob/issues/52) & [Sonos supported audio formats](https://docs.sonos.com/docs/supported-audio-formats)
|
||||
|
||||
In this case you could set;
|
||||
If you simple wish to have a custom client that transcodes from audio/flac->audio/flac then you could set;
|
||||
|
||||
```bash
|
||||
BNB_SUBSONIC_CUSTOM_CLIENTS="audio/flac"
|
||||
|
||||
7680
package-lock.json
generated
Normal file
7680
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
88
package.json
88
package.json
@@ -7,66 +7,72 @@
|
||||
"license": "GPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@svrooij/sonos": "^2.5.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/jws": "^3.2.5",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/node": "^16.11.7",
|
||||
"@types/randomstring": "^1.1.8",
|
||||
"@types/sharp": "^0.31.1",
|
||||
"@types/underscore": "^1.11.4",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@types/xmldom": "0.1.31",
|
||||
"axios": "^1.3.4",
|
||||
"dayjs": "^1.11.7",
|
||||
"eta": "^2.0.1",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/jws": "^3.2.9",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/node": "^20.11.5",
|
||||
"@types/randomstring": "^1.1.11",
|
||||
"@types/underscore": "^1.11.15",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@types/xmldom": "0.1.34",
|
||||
"axios": "^1.6.5",
|
||||
"dayjs": "^1.11.10",
|
||||
"eta": "^2.2.0",
|
||||
"express": "^4.18.2",
|
||||
"fp-ts": "^2.13.1",
|
||||
"fs-extra": "^11.1.0",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"fp-ts": "^2.16.2",
|
||||
"fs-extra": "^11.2.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"jws": "^4.0.0",
|
||||
"libxmljs2": "^0.31.0",
|
||||
"libxmljs2": "^0.33.0",
|
||||
"morgan": "^1.10.0",
|
||||
"node-html-parser": "^6.1.5",
|
||||
"randomstring": "^1.2.3",
|
||||
"sharp": "^0.31.3",
|
||||
"node-html-parser": "^6.1.12",
|
||||
"randomstring": "^1.3.0",
|
||||
"sharp": "^0.33.2",
|
||||
"soap": "^1.0.0",
|
||||
"ts-md5": "^1.3.1",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript": "^5.3.3",
|
||||
"underscore": "^1.13.6",
|
||||
"urn-lib": "^2.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.8.2",
|
||||
"uuid": "^9.0.1",
|
||||
"winston": "^3.11.0",
|
||||
"xmldom-ts": "^0.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.4",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"chai": "^4.3.7",
|
||||
"get-port": "^6.1.2",
|
||||
"image-js": "^0.35.3",
|
||||
"jest": "^29.4.3",
|
||||
"nodemon": "^2.0.21",
|
||||
"supertest": "^6.3.3",
|
||||
"@types/chai": "^4.3.11",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@types/tmp": "^0.2.6",
|
||||
"chai": "^5.0.0",
|
||||
"get-port": "^7.0.0",
|
||||
"image-js": "^0.35.5",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.0.3",
|
||||
"supertest": "^6.3.4",
|
||||
"tmp": "^0.2.1",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-jest": "^29.1.2",
|
||||
"ts-mockito": "^2.6.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"xmldom-ts": "^0.3.1",
|
||||
"xpath-ts": "^1.3.13"
|
||||
},
|
||||
"overrides": {
|
||||
"axios-ntlm": "npm:dry-uninstall",
|
||||
"axios": "$axios",
|
||||
"@svrooij/sonos": {
|
||||
"fast-xml-parser": "^3.21.1"
|
||||
}
|
||||
},
|
||||
"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_SEED_HOST=$BNB_DEV_SONOS_DEVICE_IP BNB_SONOS_SERVICE_NAME=z_bonobDev BNB_SONOS_DEVICE_DISCOVERY=true 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",
|
||||
"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_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",
|
||||
"testw": "jest --watch",
|
||||
"gitinfo": "git describe --tags > .gitinfo"
|
||||
},
|
||||
"packageManager": "yarn@1.22.19"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -176,7 +176,7 @@ export function autoDiscoverySonos(sonosSeedHost?: string): Sonos {
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error(`Failed looking for sonos devices`, { cause: e });
|
||||
logger.error(`Failed looking for sonos devices - ${e}`, { cause: e });
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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:
|
||||
@@ -162,6 +163,7 @@ export type song = {
|
||||
bitRate: number | undefined;
|
||||
suffix: string | undefined;
|
||||
contentType: string | undefined;
|
||||
transcodedContentType: string | undefined;
|
||||
type: string | undefined;
|
||||
userRating: number | undefined;
|
||||
starred: string | undefined;
|
||||
@@ -272,7 +274,7 @@ export const artistImageURN = (
|
||||
export const asTrack = (album: Album, song: song): Track => ({
|
||||
id: song.id,
|
||||
name: song.title,
|
||||
mimeType: song.contentType!,
|
||||
mimeType: song.transcodedContentType ? song.transcodedContentType : song.contentType!,
|
||||
duration: song.duration || 0,
|
||||
number: song.track || 0,
|
||||
genre: maybeAsGenre(song.genre),
|
||||
@@ -344,28 +346,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 +414,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 +435,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",
|
||||
@@ -955,6 +957,7 @@ export class Subsonic implements MusicService {
|
||||
};
|
||||
|
||||
if (credentials.type == "navidrome") {
|
||||
// todo: there does not seem to be a test for this??
|
||||
return Promise.resolve({
|
||||
...genericSubsonic,
|
||||
flavour: () => "navidrome",
|
||||
@@ -963,7 +966,7 @@ export class Subsonic implements MusicService {
|
||||
TE.tryCatch(
|
||||
() =>
|
||||
axios.post(
|
||||
`${this.url}/auth/login`,
|
||||
this.url.append({ pathname: '/auth/login' }).href(),
|
||||
_.pick(credentials, "username", "password")
|
||||
),
|
||||
() => new AuthFailure("Failed to get bearerToken")
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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", () => {
|
||||
@@ -321,6 +322,7 @@ const asSongJson = (track: Track) => ({
|
||||
size: "5624132",
|
||||
suffix: "mp3",
|
||||
contentType: track.mimeType,
|
||||
transcodedContentType: undefined,
|
||||
isVideo: "false",
|
||||
path: "ACDC/High voltage/ACDC - The Jack.mp3",
|
||||
albumId: track.album.id,
|
||||
@@ -685,10 +687,33 @@ describe("asTrack", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the song has a transcodedContentType", () => {
|
||||
const album = anAlbum();
|
||||
|
||||
describe("with an undefined value", () => {
|
||||
const track = aTrack({ mimeType: "sourced-from/mimeType" });
|
||||
|
||||
it("should fall back on the default mime", () => {
|
||||
const result = asTrack(album, { ...asSongJson(track), transcodedContentType: undefined });
|
||||
expect(result.mimeType).toEqual("sourced-from/mimeType")
|
||||
});
|
||||
});
|
||||
|
||||
describe("with a value", () => {
|
||||
const track = aTrack({ mimeType: "sourced-from/mimeType" });
|
||||
|
||||
it("should use the transcoded value", () => {
|
||||
const result = asTrack(album, { ...asSongJson(track), transcodedContentType: "sourced-from/transcodedContentType" });
|
||||
expect(result.mimeType).toEqual("sourced-from/transcodedContentType")
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
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 +781,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 +802,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 +827,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 +873,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 +901,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,
|
||||
});
|
||||
@@ -927,6 +952,34 @@ describe("Subsonic", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("bearerToken", () => {
|
||||
describe("when flavour is generic subsonic", () => {
|
||||
it("should return undefined", async () => {
|
||||
const credentials = { username: "foo", password: "bar" };
|
||||
const token = { ...credentials, type: "subsonic", bearer: undefined }
|
||||
const client = await subsonic.login(asToken(token));
|
||||
|
||||
const bearerToken = await pipe(client.bearerToken(credentials))();
|
||||
expect(bearerToken).toStrictEqual(E.right(undefined));
|
||||
});
|
||||
});
|
||||
|
||||
describe("when flavour is navidrome", () => {
|
||||
it("should get a bearerToken from navidrome", async () => {
|
||||
const credentials = { username: "foo", password: "bar" };
|
||||
const token = { ...credentials, type: "navidrome", bearer: undefined }
|
||||
const client = await subsonic.login(asToken(token));
|
||||
|
||||
mockPOST.mockImplementationOnce(() => Promise.resolve(ok({ token: 'theBearerToken' })))
|
||||
|
||||
const bearerToken = await pipe(client.bearerToken(credentials))();
|
||||
expect(bearerToken).toStrictEqual(E.right('theBearerToken'));
|
||||
|
||||
expect(axios.post).toHaveBeenCalledWith(url.append({ pathname: '/auth/login' }).href(), credentials)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getting genres", () => {
|
||||
describe("when there are none", () => {
|
||||
beforeEach(() => {
|
||||
@@ -941,7 +994,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 +1021,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 +1056,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 +1112,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 +1120,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 +1171,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 +1179,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 +1224,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 +1232,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 +1278,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 +1286,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 +1329,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 +1337,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 +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,
|
||||
@@ -1335,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,
|
||||
@@ -1379,7 +1432,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 +1440,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 +1485,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 +1493,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 +1536,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 +1544,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 +1585,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 +1593,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 +1714,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 +1755,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 +1783,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 +1839,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 +1891,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 +1942,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 +1984,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 +2026,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 +2077,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 +2127,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 +2192,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 +2243,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 +2316,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 +2373,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 +2429,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 +2495,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 +2559,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 +2621,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 +2673,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 +2751,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 +2798,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 +2833,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 +2884,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 +2892,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 +2931,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 +2939,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 +3086,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 +3192,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 +3235,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 +3277,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 +3320,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 +3356,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 +3482,7 @@ describe("Subsonic", () => {
|
||||
});
|
||||
|
||||
expect(axios.get).toHaveBeenCalledWith(
|
||||
`${url}/rest/getCoverArt`,
|
||||
url.append({ pathname: '/rest/getCoverArt' }).href(),
|
||||
{
|
||||
params: asURLSearchParams({
|
||||
...authParams,
|
||||
@@ -3495,7 +3548,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 +3581,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 +3640,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 +3701,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 +3768,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 +3797,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 +3823,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 +3852,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 +3880,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 +3914,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 +3940,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 +3976,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 +4026,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 +4052,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 +4098,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 +4170,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 +4196,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 +4227,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 +4252,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 +4272,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 +4357,7 @@ describe("Subsonic", () => {
|
||||
],
|
||||
});
|
||||
|
||||
expect(mockGET).toHaveBeenCalledWith(`${url}/rest/getPlaylist`, {
|
||||
expect(mockGET).toHaveBeenCalledWith(url.append({ pathname: '/rest/getPlaylist' }).href(), {
|
||||
params: asURLSearchParams({
|
||||
...authParamsPlusJson,
|
||||
id,
|
||||
@@ -4331,7 +4384,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 +4412,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 +4436,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 +4461,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 +4486,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 +4533,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 +4603,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 +4630,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 +4697,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 +4764,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 +4804,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",
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": [
|
||||
"./typings",
|
||||
"node_modules/@types"
|
||||
"./node_modules/@types"
|
||||
]
|
||||
/* List of folders to include type definitions from. */,
|
||||
// "types": ["src/customTypes/scale-that-svg.d.ts"], /* Type declaration files to be included in compilation. */
|
||||
|
||||
Reference in New Issue
Block a user