mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9786d9f1dd | ||
|
|
a9d88bd9eb | ||
|
|
f6fc7ab920 |
@@ -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 && \
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_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",
|
||||
"register-dev": "ts-node ./src/register.ts http://${BNB_DEV_HOST_IP}:4534",
|
||||
"test": "jest",
|
||||
"gitinfo": "git describe --tags > .gitinfo"
|
||||
},
|
||||
|
||||
43
src/i8n.ts
43
src/i8n.ts
@@ -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",
|
||||
|
||||
12
src/smapi.ts
12
src/smapi.ts
@@ -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: []
|
||||
};
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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"]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user