import { hostname } from "os"; import logger from "./logger"; import url from "./url_builder"; export const WORD = /^\w+$/; export const COLOR = /^#?\w+$/; type EnvVarOpts = { default: T | undefined; legacy: string[] | undefined; validationPattern: RegExp | undefined; parser: ((value: string) => T) | undefined }; export function envVar( name: string, opts: Partial> = { default: undefined, legacy: undefined, validationPattern: undefined, parser: undefined } ): T { const result = [name, ...(opts.legacy || [])] .map((it) => ({ key: it, value: process.env[it] })) .find((it) => it.value); if ( result && result.value && opts.validationPattern && !result.value.match(opts.validationPattern) ) { throw `Invalid value specified for '${name}', must match ${opts.validationPattern}`; } if(result && result.value && result.key != name) { logger.warn(`Configuration key '${result.key}' is deprecated, replace with '${name}'`) } let value: T | undefined = undefined; if(result?.value && opts.parser) { value = opts.parser(result?.value) } else if(result?.value) value = result?.value as any as T return value == undefined ? opts.default as T : value; } export const bnbEnvVar = (key: string, opts: Partial> = {}) => envVar(`BNB_${key}`, { ...opts, legacy: [`BONOB_${key}`, ...(opts.legacy || [])], }); const asBoolean = (value: string) => value == "true"; const asInt = (value: string) => Number.parseInt(value); export default function () { const port = bnbEnvVar("PORT", { default: 4534, parser: asInt })!; const bonobUrl = bnbEnvVar("URL", { legacy: ["BONOB_WEB_ADDRESS"], default: `http://${hostname()}:${port}`, })!; if (bonobUrl.match("localhost")) { logger.error( "BNB_URL containing localhost is almost certainly incorrect, sonos devices will not be able to communicate with bonob using localhost, please specify either public IP or DNS entry" ); process.exit(1); } return { port, bonobUrl: url(bonobUrl), secret: bnbEnvVar("SECRET", { default: "bonob" })!, authTimeout: bnbEnvVar("AUTH_TIMEOUT", { default: "1h" })!, icons: { foregroundColor: bnbEnvVar("ICON_FOREGROUND_COLOR", { validationPattern: COLOR, }), backgroundColor: bnbEnvVar("ICON_BACKGROUND_COLOR", { validationPattern: COLOR, }), }, logRequests: bnbEnvVar("SERVER_LOG_REQUESTS", { default: false, parser: asBoolean }), sonos: { serviceName: bnbEnvVar("SONOS_SERVICE_NAME", { default: "bonob" })!, discovery: { enabled: bnbEnvVar("SONOS_DEVICE_DISCOVERY", { default: true, parser: asBoolean }), seedHost: bnbEnvVar("SONOS_SEED_HOST"), }, autoRegister: bnbEnvVar("SONOS_AUTO_REGISTER", { default: false, parser: asBoolean }), sid: bnbEnvVar("SONOS_SERVICE_ID", { default: 246, parser: asInt }), }, subsonic: { url: url(bnbEnvVar("SUBSONIC_URL", { legacy: ["BONOB_NAVIDROME_URL"], default: `http://${hostname()}:4533` })!), customClientsFor: bnbEnvVar("SUBSONIC_CUSTOM_CLIENTS", { legacy: ["BONOB_NAVIDROME_CUSTOM_CLIENTS"] }), artistImageCache: bnbEnvVar("SUBSONIC_ARTIST_IMAGE_CACHE"), }, scrobbleTracks: bnbEnvVar("SCROBBLE_TRACKS", { default: true, parser: asBoolean }), reportNowPlaying: bnbEnvVar("REPORT_NOW_PLAYING", { default: true, parser: asBoolean }), }; }