diff --git a/.gitignore b/.gitignore index 11df0f3..fe71f0e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .vscode build ignore +.ignore node_modules .yarn/* !.yarn/patches diff --git a/package.json b/package.json index afa80e7..ceec5da 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "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", + "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", diff --git a/src/config.ts b/src/config.ts index 7a65623..ad11998 100644 --- a/src/config.ts +++ b/src/config.ts @@ -58,6 +58,8 @@ const asBoolean = (value: string) => value == "true"; const asInt = (value: string) => Number.parseInt(value); +const asStringNoTrailingSlash = (value: string) => value.replace(/\/$/, ""); + export default function () { const port = bnbEnvVar("PORT", { default: 4534, parser: asInt })!; const bonobUrl = bnbEnvVar("URL", { @@ -98,7 +100,8 @@ export default function () { sid: bnbEnvVar("SONOS_SERVICE_ID", { default: 246, parser: asInt }), }, subsonic: { - url: bnbEnvVar("SUBSONIC_URL", { legacy: ["BONOB_NAVIDROME_URL"], default: `http://${hostname()}:4533` })!, + // todo: why isnt this a url like bonobUrl above? + url: bnbEnvVar("SUBSONIC_URL", { legacy: ["BONOB_NAVIDROME_URL"], default: `http://${hostname()}:4533`, parser: asStringNoTrailingSlash })!, customClientsFor: bnbEnvVar("SUBSONIC_CUSTOM_CLIENTS", { legacy: ["BONOB_NAVIDROME_CUSTOM_CLIENTS"] }), artistImageCache: bnbEnvVar("SUBSONIC_ARTIST_IMAGE_CACHE"), }, diff --git a/src/server.ts b/src/server.ts index d2b3ac7..2d62af9 100644 --- a/src/server.ts +++ b/src/server.ts @@ -450,8 +450,11 @@ function server( .forEach(([header, value]) => { res.setHeader(header, value!); }); - if (sendStream) stream.stream.pipe(filter).pipe(res); - else res.send(); + res.on('close', () => { + stream.stream.destroy() + }); + if (sendStream) stream.stream.pipe(filter).pipe(res) + else res.send() }); }; diff --git a/tests/config.test.ts b/tests/config.test.ts index 1988410..942cec4 100644 --- a/tests/config.test.ts +++ b/tests/config.test.ts @@ -393,6 +393,14 @@ describe("config", () => { expect(config().subsonic.url).toEqual(url); }); }); + + describe(`when ${k} is specified with trailing slash`, () => { + it(`should remove the trailing slash and use it for ${k}`, () => { + const url = "http://navidrome.example.com:1234"; + process.env[k] = `${url}/`; + expect(config().subsonic.url).toEqual(url); + }); + }); }); }); diff --git a/tests/server.test.ts b/tests/server.test.ts index c636607..eae291c 100644 --- a/tests/server.test.ts +++ b/tests/server.test.ts @@ -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); }); }); });