From ee8b371850a085133b230c66af0c589e23140006 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 11 Oct 2024 09:23:02 -0400 Subject: [PATCH 1/4] fix: Missing tsconfig and other root files for some reason?? --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 97a3d47..200e33d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,7 +88,7 @@ RUN npm run docs:install && npm run build && rm -rf node_modules && rm -rf docsi FROM base as app -COPY --chown=abc:abc package*.json ./ +COPY --chown=abc:abc *.json *.js *.ts index.html ./ COPY --chown=abc:abc patches ./patches COPY --from=build --chown=abc:abc /app/dist /app/dist COPY --from=build --chown=abc:abc /app/src /app/src From f7fa9cd3306947ee5601bb42ce7f9028f0908f75 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 11 Oct 2024 09:27:12 -0400 Subject: [PATCH 2/4] fix: Guard against ts-schema generation errors * Check if generator is null and throw * Check if schema is null before trying to validate, will make errors less cryptic --- src/backend/utils/SchemaUtils.ts | 6 +++++- src/backend/utils/ValidationUtils.ts | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/SchemaUtils.ts b/src/backend/utils/SchemaUtils.ts index 9739de8..2c02624 100644 --- a/src/backend/utils/SchemaUtils.ts +++ b/src/backend/utils/SchemaUtils.ts @@ -28,6 +28,9 @@ export const getTsConfigProgram = (): TJS.Program => { export const getTsConfigGenerator = (): TJS.JsonSchemaGenerator => { if(generatorFromConfig === undefined) { generatorFromConfig = buildSchemaGenerator(getTsConfigProgram()); + if(generatorFromConfig === null) { + throw new Error('Schema generator had errors! See console output.'); + } } return generatorFromConfig; } @@ -37,7 +40,8 @@ export const getTypeSchemaFromConfigGenerator = (type: string): TJS.Definition | } export const defaultGeneratorArgs: TJS.PartialArgs = { - required: true, + required: true, + //ignoreErrors: true, titles: true, validationKeywords: ['deprecationMessage'], constAsEnum: true, diff --git a/src/backend/utils/ValidationUtils.ts b/src/backend/utils/ValidationUtils.ts index 5ecbffa..c169f37 100644 --- a/src/backend/utils/ValidationUtils.ts +++ b/src/backend/utils/ValidationUtils.ts @@ -10,6 +10,9 @@ export const createAjvFactory = (logger: Logger): AjvNS.default => { } export const validateJson = (config: object, schema: Schema, logger: Logger): T => { const ajv = createAjvFactory(logger); + if(schema === null) { + throw new Error('Schema cannot be null'); + } const valid = ajv.validate(schema, config); if (valid) { return config as unknown as T; From de1a9c35ec0a05033af1518bb59801fc134dbc6b Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 11 Oct 2024 09:28:01 -0400 Subject: [PATCH 3/4] fix: Add missing express types for prod dependencies Required for ts-schema generator to correctly work since we use it in config definitions --- package-lock.json | 12 ++++-------- package.json | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f7270f..6151df9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@react-nano/use-event-source": "^0.13.0", "@reduxjs/toolkit": "^1.9.5", "@supercharge/promise-pool": "^3.0.0", + "@types/express-serve-static-core": "^4.19.6", "address": "^1.2.2", "ajv": "^8.12.0", "autoprefixer": "^10.4.17", @@ -2533,7 +2534,6 @@ "version": "4.19.6", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", - "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -2620,8 +2620,7 @@ "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/mocha": { "version": "9.1.1", @@ -2674,14 +2673,12 @@ "node_modules/@types/qs": { "version": "6.9.16", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", - "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", - "dev": true + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { "version": "18.3.11", @@ -2722,7 +2719,6 @@ "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, "dependencies": { "@types/mime": "^1", "@types/node": "*" diff --git a/package.json b/package.json index 17dff21..6ef21ef 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@react-nano/use-event-source": "^0.13.0", "@reduxjs/toolkit": "^1.9.5", "@supercharge/promise-pool": "^3.0.0", + "@types/express-serve-static-core": "^4.19.6", "address": "^1.2.2", "ajv": "^8.12.0", "autoprefixer": "^10.4.17", From 908d7d41775d39807afcfabb95bbcd188b1702cb Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 11 Oct 2024 12:28:55 -0400 Subject: [PATCH 4/4] fix: Replace typescript-json-schema with ts-json-schema-generator Fixes a lot of headaches: * vega is more up to date and extensible * no more hacky regex for reference names * complete control over parsing and formatting (const as enum) * does not duplicate typescript as dependency * should properly throw errors on schema generation instead of just logging to console * move schema static files into programmatic creation instead of package scripts * fix types being removed in prod which caused schema generation errors --- Dockerfile | 4 +- package-lock.json | 289 +- package.json | 9 +- patches/ts-json-schema-generator+2.3.0.patch | 26 + patches/typescript-json-schema+0.61.0.patch | 13 - src/backend/common/schema/aio-client.json | 734 +--- src/backend/common/schema/aio-source.json | 2864 +------------ src/backend/common/schema/aio.json | 3878 +----------------- src/backend/common/schema/client.json | 669 +-- src/backend/common/schema/source.json | 2660 +----------- src/backend/index.ts | 4 +- src/backend/scrobblers/ScrobbleClients.ts | 2 +- src/backend/sources/ScrobbleSources.ts | 2 +- src/backend/utils/SchemaStaticUtil.ts | 19 + src/backend/utils/SchemaUtils.ts | 82 +- 15 files changed, 248 insertions(+), 11007 deletions(-) create mode 100644 patches/ts-json-schema-generator+2.3.0.patch delete mode 100644 patches/typescript-json-schema+0.61.0.patch create mode 100644 src/backend/utils/SchemaStaticUtil.ts diff --git a/Dockerfile b/Dockerfile index 200e33d..1850228 100644 --- a/Dockerfile +++ b/Dockerfile @@ -106,8 +106,8 @@ ENV APP_VERSION=$APP_BUILD_VERSION RUN npm ci --omit=dev \ && npm cache clean --force \ && chown -R abc:abc node_modules \ - && rm -rf node_modules/@types \ - /root/.cache + && rm -rf /root/.cache + ARG webPort=9078 ENV PORT=$webPort diff --git a/package-lock.json b/package-lock.json index 6151df9..23f50f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,8 +75,8 @@ "superagent": "^8.0.9", "tailwindcss": "^3.4.4", "toad-scheduler": "^3.0.0", + "ts-json-schema-generator": "^2.3.0", "tsx": "^4.7.0", - "typescript-json-schema": "^0.61.0", "vite-express": "^0.16.0", "vlc-client": "^1.1.1", "xml2js": "0.6.0", @@ -583,6 +583,8 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -594,6 +596,8 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2348,22 +2352,30 @@ "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "optional": true, + "peer": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "optional": true, + "peer": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "optional": true, + "peer": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "optional": true, + "peer": true }, "node_modules/@tsconfig/node18": { "version": "1.0.3", @@ -3087,6 +3099,7 @@ "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -3107,6 +3120,8 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "optional": true, + "peer": true, "dependencies": { "acorn": "^8.11.0" }, @@ -4103,7 +4118,9 @@ "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "optional": true, + "peer": true }, "node_modules/croner": { "version": "7.0.8", @@ -5388,6 +5405,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -6907,7 +6925,9 @@ "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "optional": true, + "peer": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -8160,11 +8180,6 @@ "node": ">=10" } }, - "node_modules/path-equal": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", - "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9112,6 +9127,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -10354,10 +10370,116 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "node_modules/ts-json-schema-generator": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-2.3.0.tgz", + "integrity": "sha512-t4lBQAwZc0sOJq9LJt3NgbznIcslVnm0JeEMFq8qIRklpMRY8jlYD0YmnRWbqBKANxkby91P1XanSSlSOFpUmg==", + "dependencies": { + "@types/json-schema": "^7.0.15", + "commander": "^12.0.0", + "glob": "^10.3.12", + "json5": "^2.2.3", + "normalize-path": "^3.0.0", + "safe-stable-stringify": "^2.4.3", + "tslib": "^2.6.2", + "typescript": "^5.4.5" + }, + "bin": { + "ts-json-schema-generator": "bin/ts-json-schema-generator.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ts-json-schema-generator/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ts-json-schema-generator/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-json-schema-generator/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ts-json-schema-generator/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/ts-json-schema-generator/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/ts-json-schema-generator/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ts-json-schema-generator/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "optional": true, + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -10399,12 +10521,16 @@ "node_modules/ts-node/node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "optional": true, + "peer": true }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "optional": true, + "peer": true, "engines": { "node": ">=0.3.1" } @@ -10412,8 +10538,7 @@ "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/tsx": { "version": "4.19.1", @@ -10535,133 +10660,6 @@ "resolved": "https://registry.npmjs.org/typescript-event-target/-/typescript-event-target-1.1.1.tgz", "integrity": "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg==" }, - "node_modules/typescript-json-schema": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.61.0.tgz", - "integrity": "sha512-sYKnLJjvh9ljdSQkh91LM9PEzgzrgnYfvU226IauISFd+379VCti/VtAFXd00Z9euLkVffh5LRTAO8eamsxUlw==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/node": "^16.9.2", - "glob": "^7.1.7", - "path-equal": "^1.2.5", - "safe-stable-stringify": "^2.2.0", - "ts-node": "^10.9.1", - "typescript": "~5.1.0", - "yargs": "^17.1.1" - }, - "bin": { - "typescript-json-schema": "bin/typescript-json-schema" - } - }, - "node_modules/typescript-json-schema/node_modules/@types/node": { - "version": "16.18.113", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.113.tgz", - "integrity": "sha512-4jHxcEzSXpF1cBNxogs5FVbVSFSKo50sFCn7Xg7vmjJTbWFWgeuHW3QnoINlfmfG++MFR/q97RZE5RQXKeT+jg==" - }, - "node_modules/typescript-json-schema/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/typescript-json-schema/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/typescript-json-schema/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typescript-json-schema/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/typescript-json-schema/node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-json-schema/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/typescript-json-schema/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/typescript-json-schema/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -10804,7 +10802,9 @@ "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "optional": true, + "peer": true }, "node_modules/vary": { "version": "1.1.2", @@ -11556,6 +11556,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } @@ -11667,6 +11668,8 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "optional": true, + "peer": true, "engines": { "node": ">=6" } diff --git a/package.json b/package.json index 6ef21ef..16c30fa 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,7 @@ "type": "module", "description": "scrobble plays from multiple sources to multiple clients", "scripts": { - "schema": "npm run -s schema-aio & npm run -s schema-source & npm run -s schema-client & npm run -s schema-aiosource & npm run -s schema-aioclient", - "schema-client": "typescript-json-schema src/backend/tsconfig.json ClientConfig --out src/backend/common/schema/client.json --required --titles --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum", - "schema-source": "typescript-json-schema src/backend/tsconfig.json SourceConfig --out src/backend/common/schema/source.json --required --titles --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum", - "schema-aio": "typescript-json-schema src/backend/tsconfig.json AIOConfig --out src/backend/common/schema/aio.json --required --titles --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum", - "schema-aiosource": "typescript-json-schema src/backend/tsconfig.json AIOSourceConfig --out src/backend/common/schema/aio-source.json --titles --required --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum", - "schema-aioclient": "typescript-json-schema src/backend/tsconfig.json AIOClientConfig --out src/backend/common/schema/aio-client.json --titles --required --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum", + "schema": "tsx src/backend/utils/SchemaStaticUtil.ts", "circular": "madge --circular --extensions ts src/index.ts", "test": "npm run -s test:backend", "test:backend": "mocha --reporter spec", @@ -110,8 +105,8 @@ "superagent": "^8.0.9", "tailwindcss": "^3.4.4", "toad-scheduler": "^3.0.0", + "ts-json-schema-generator": "^2.3.0", "tsx": "^4.7.0", - "typescript-json-schema": "^0.61.0", "vite-express": "^0.16.0", "vlc-client": "^1.1.1", "xml2js": "0.6.0", diff --git a/patches/ts-json-schema-generator+2.3.0.patch b/patches/ts-json-schema-generator+2.3.0.patch new file mode 100644 index 0000000..efed168 --- /dev/null +++ b/patches/ts-json-schema-generator+2.3.0.patch @@ -0,0 +1,26 @@ +diff --git a/node_modules/ts-json-schema-generator/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js b/node_modules/ts-json-schema-generator/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js +index 107dc62..6b7c311 100644 +--- a/node_modules/ts-json-schema-generator/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js ++++ b/node_modules/ts-json-schema-generator/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js +@@ -49,7 +49,7 @@ class ExtendedAnnotationsReader extends BasicAnnotationsReader_js_1.BasicAnnotat + .replace(/\r/g, "") + .trim(); + const description = markdownDescription.replace(/(?<=[^\n])\n(?=[^\n*-])/g, " ").trim(); +- return this.markdownDescription ? { description, markdownDescription } : { description }; ++ return this.markdownDescription ? { description: markdownDescription } : { description }; + } + getTypeAnnotation(node) { + const symbol = (0, symbolAtNode_js_1.symbolAtNode)(node); +diff --git a/node_modules/ts-json-schema-generator/src/AnnotationsReader/ExtendedAnnotationsReader.ts b/node_modules/ts-json-schema-generator/src/AnnotationsReader/ExtendedAnnotationsReader.ts +index ba8fd57..806396c 100644 +--- a/node_modules/ts-json-schema-generator/src/AnnotationsReader/ExtendedAnnotationsReader.ts ++++ b/node_modules/ts-json-schema-generator/src/AnnotationsReader/ExtendedAnnotationsReader.ts +@@ -57,7 +57,7 @@ export class ExtendedAnnotationsReader extends BasicAnnotationsReader { + + const description = markdownDescription.replace(/(?<=[^\n])\n(?=[^\n*-])/g, " ").trim(); + +- return this.markdownDescription ? { description, markdownDescription } : { description }; ++ return this.markdownDescription ? { description: markdownDescription } : { description }; + } + private getTypeAnnotation(node: ts.Node): Annotations | undefined { + const symbol = symbolAtNode(node); diff --git a/patches/typescript-json-schema+0.61.0.patch b/patches/typescript-json-schema+0.61.0.patch deleted file mode 100644 index c3ae945..0000000 --- a/patches/typescript-json-schema+0.61.0.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/typescript-json-schema/dist/typescript-json-schema.js b/node_modules/typescript-json-schema/dist/typescript-json-schema.js -index 5b5ecec..1e48e77 100644 ---- a/node_modules/typescript-json-schema/dist/typescript-json-schema.js -+++ b/node_modules/typescript-json-schema/dist/typescript-json-schema.js -@@ -55,7 +55,7 @@ var crypto_1 = require("crypto"); - var ts = require("typescript"); - var path_equal_1 = require("path-equal"); - var vm = require("vm"); --var REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g; -+var REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"(, \{ assert: \{ "resolution-mode": "(import|require)" \} \})?\)|".*?")\.| /g;// /(\bimport\(".*?"\)|".*?")\.| /g; - var REGEX_TSCONFIG_NAME = /^.*\.json$/; - var REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; - var REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; diff --git a/src/backend/common/schema/aio-client.json b/src/backend/common/schema/aio-client.json index e1ad792..60c7b2d 100644 --- a/src/backend/common/schema/aio-client.json +++ b/src/backend/common/schema/aio-client.json @@ -1,733 +1 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "ClientAIOConfig": { - "anyOf": [ - { - "$ref": "#/definitions/LastfmClientAIOConfig" - }, - { - "$ref": "#/definitions/ListenBrainzClientAIOConfig" - }, - { - "$ref": "#/definitions/MalojaClientAIOConfig" - } - ], - "title": "ClientAIOConfig" - }, - "CommonClientData": { - "title": "CommonClientData", - "type": "object" - }, - "CommonClientOptions": { - "properties": { - "checkExistingScrobbles": { - "default": true, - "description": "Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.", - "examples": [ - true - ], - "title": "checkExistingScrobbles", - "type": "boolean" - }, - "deadLetterRetries": { - "default": 1, - "description": "Number of times MS should automatically retry scrobbles in dead letter queue", - "examples": [ - 1 - ], - "title": "deadLetterRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "refreshEnabled": { - "default": true, - "description": "Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history", - "examples": [ - true - ], - "title": "refreshEnabled", - "type": "boolean" - }, - "refreshInitialCount": { - "description": "The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call.", - "title": "refreshInitialCount", - "type": "number" - }, - "refreshMinInterval": { - "default": 5000, - "description": "Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.", - "examples": [ - 5000 - ], - "title": "refreshMinInterval", - "type": "number" - }, - "refreshStaleAfter": { - "default": 60, - "description": "Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.", - "examples": [ - 60 - ], - "title": "refreshStaleAfter", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "verbose": { - "description": "Options used for increasing verbosity of logging in MS (used for debugging)", - "properties": { - "match": { - "$ref": "#/definitions/MatchLoggingOptions", - "title": "match" - } - }, - "title": "verbose", - "type": "object" - } - }, - "title": "CommonClientOptions", - "type": "object" - }, - "ConditionalSearchAndReplaceTerm": { - "properties": { - "replace": { - "description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace", - "title": "replace", - "type": "string" - }, - "search": { - "anyOf": [ - { - "$ref": "#/definitions/RegExp" - }, - { - "type": "string" - } - ], - "description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression as a string, or an actual RegExp object", - "title": "search" - }, - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "required": [ - "replace", - "search" - ], - "title": "ConditionalSearchAndReplaceTerm", - "type": "object" - }, - "LastfmClientAIOConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using LastFM as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "allOf": [ - { - "$ref": "#/definitions/CommonClientData" - }, - { - "$ref": "#/definitions/LastfmData" - } - ], - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "lastfm" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "LastfmClientAIOConfig", - "type": "object" - }, - "LastfmData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastfmData", - "type": "object" - }, - "ListenBrainzClientAIOConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using Listenbrainz as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "listenbrainz" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "ListenBrainzClientAIOConfig", - "type": "object" - }, - "ListenBrainzClientData": { - "properties": { - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzClientData", - "type": "object" - }, - "MalojaClientAIOConfig": { - "properties": { - "data": { - "$ref": "#/definitions/MalojaClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "maloja" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "MalojaClientAIOConfig", - "type": "object" - }, - "MalojaClientData": { - "properties": { - "apiKey": { - "description": "API Key for Maloja server", - "examples": [ - "myApiKey" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "url": { - "description": "URL for maloja server", - "examples": [ - "http://localhost:42010" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "apiKey", - "url" - ], - "title": "MalojaClientData", - "type": "object" - }, - "MatchLoggingOptions": { - "description": "Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging.", - "properties": { - "confidenceBreakdown": { - "default": false, - "description": "Include confidence breakdowns in track match logging, if applicable", - "examples": [ - false - ], - "title": "confidenceBreakdown", - "type": "boolean" - }, - "onMatch": { - "default": false, - "description": "Log to DEBUG when a new track DOES match an existing scrobble", - "examples": [ - false - ], - "title": "onMatch", - "type": "boolean" - }, - "onNoMatch": { - "default": false, - "description": "Log to DEBUG when a new track does NOT match an existing scrobble", - "examples": [ - false - ], - "title": "onNoMatch", - "type": "boolean" - } - }, - "title": "MatchLoggingOptions", - "type": "object" - }, - "PlayTransformConfig": { - "properties": { - "compare": { - "properties": { - "candidate": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "candidate" - }, - "existing": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "existing" - } - }, - "title": "compare", - "type": "object" - }, - "postCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "postCompare" - }, - "preCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "preCompare" - } - }, - "title": "PlayTransformConfig", - "type": "object" - }, - "PlayTransformOptions": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformConfig" - }, - { - "properties": { - "log": { - "enum": [ - "all", - false, - true - ], - "title": "log" - } - }, - "type": "object" - } - ], - "title": "PlayTransformOptions" - }, - "PlayTransformParts": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformPartsAtomic" - }, - { - "properties": { - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "type": "object" - } - ], - "title": "PlayTransformParts" - }, - "PlayTransformPartsAtomic": { - "properties": { - "album": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "album", - "type": "array" - }, - "artists": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "artists", - "type": "array" - }, - "title": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "title", - "type": "array" - } - }, - "title": "PlayTransformPartsAtomic", - "type": "object" - }, - "PlayTransformPartsConfig": { - "anyOf": [ - { - "items": { - "$ref": "#/definitions/PlayTransformParts" - }, - "type": "array" - }, - { - "$ref": "#/definitions/PlayTransformParts" - } - ], - "title": "PlayTransformPartsConfig" - }, - "RegExp": { - "properties": { - "dotAll": { - "title": "dotAll", - "type": "boolean" - }, - "flags": { - "title": "flags", - "type": "string" - }, - "global": { - "title": "global", - "type": "boolean" - }, - "hasIndices": { - "title": "hasIndices", - "type": "boolean" - }, - "ignoreCase": { - "title": "ignoreCase", - "type": "boolean" - }, - "lastIndex": { - "title": "lastIndex", - "type": "number" - }, - "multiline": { - "title": "multiline", - "type": "boolean" - }, - "source": { - "title": "source", - "type": "string" - }, - "sticky": { - "title": "sticky", - "type": "boolean" - }, - "unicode": { - "title": "unicode", - "type": "boolean" - } - }, - "required": [ - "dotAll", - "flags", - "global", - "hasIndices", - "ignoreCase", - "lastIndex", - "multiline", - "source", - "sticky", - "unicode" - ], - "title": "RegExp", - "type": "object" - }, - "RequestRetryOptions": { - "properties": { - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - } - }, - "title": "RequestRetryOptions", - "type": "object" - }, - "SearchAndReplaceTerm": { - "anyOf": [ - { - "$ref": "#/definitions/ConditionalSearchAndReplaceTerm" - }, - { - "type": "string" - } - ], - "title": "SearchAndReplaceTerm" - }, - "WhenParts": { - "properties": { - "album": { - "title": "album", - "type": "string" - }, - "artists": { - "title": "artists", - "type": "string" - }, - "title": { - "title": "title", - "type": "string" - } - }, - "title": "WhenParts", - "type": "object" - } - }, - "properties": { - "clientDefaults": { - "$ref": "#/definitions/RequestRetryOptions", - "title": "clientDefaults" - }, - "clients": { - "items": { - "$ref": "#/definitions/ClientAIOConfig" - }, - "title": "clients", - "type": "array" - } - }, - "type": "object" -} - +{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/AIOClientConfig","definitions":{"AIOClientConfig":{"type":"object","properties":{"clientDefaults":{"$ref":"#/definitions/RequestRetryOptions"},"clients":{"type":"array","items":{"$ref":"#/definitions/ClientAIOConfig"}}}},"RequestRetryOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]}}},"ClientAIOConfig":{"anyOf":[{"$ref":"#/definitions/MalojaClientAIOConfig"},{"$ref":"#/definitions/LastfmClientAIOConfig"},{"$ref":"#/definitions/ListenBrainzClientAIOConfig"}]},"MalojaClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/MalojaClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"type":{"type":"string","enum":["maloja"]}},"required":["data","name","type"]},"MalojaClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for maloja server","examples":["http://localhost:42010"]},"apiKey":{"type":"string","description":"API Key for Maloja server","examples":["myApiKey"]}},"required":["url","apiKey"]},"CommonClientOptions":{"type":"object","properties":{"refreshEnabled":{"type":"boolean","description":"Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history","default":true,"examples":[true]},"refreshStaleAfter":{"type":"number","description":"Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.","examples":[60],"default":60},"refreshMinInterval":{"type":"number","description":"Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.","default":5000,"examples":[5000]},"refreshInitialCount":{"type":"number","description":"The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call."},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"checkExistingScrobbles":{"type":"boolean","description":"Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.","default":true,"examples":[true]},"verbose":{"type":"object","properties":{"match":{"$ref":"#/definitions/MatchLoggingOptions"}},"description":"Options used for increasing verbosity of logging in MS (used for debugging)"},"deadLetterRetries":{"type":"number","description":"Number of times MS should automatically retry scrobbles in dead letter queue","default":1,"examples":[1]},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"MatchLoggingOptions":{"type":"object","properties":{"onNoMatch":{"type":"boolean","description":"Log to DEBUG when a new track does NOT match an existing scrobble","default":false,"examples":[false]},"onMatch":{"type":"boolean","description":"Log to DEBUG when a new track DOES match an existing scrobble","default":false,"examples":[false]},"confidenceBreakdown":{"type":"boolean","description":"Include confidence breakdowns in track match logging, if applicable","default":false,"examples":[false]}},"description":"Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging."},"PlayTransformOptions":{"type":"object","properties":{"log":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["all"]}]},"preCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"compare":{"type":"object","properties":{"candidate":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"existing":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"postCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"PlayTransformPartsConfig":{"anyOf":[{"$ref":"#/definitions/PlayTransformPartsArray%3CSearchAndReplaceTerm%3E"},{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}]},"PlayTransformPartsArray":{"type":"array","items":{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}},"PlayTransformParts":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"title":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"artists":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"album":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}}}},"WhenConditionsConfig":{"$ref":"#/definitions/WhenConditions%3Cstring%3E"},"WhenConditions":{"type":"array","items":{"$ref":"#/definitions/WhenParts%3Cstring%3E"}},"WhenParts":{"$ref":"#/definitions/PlayTransformPartsAtomic%3Cstring%3E"},"PlayTransformPartsAtomic":{"type":"object","properties":{"title":{"type":"string"},"artists":{"type":"string"},"album":{"type":"string"}}},"SearchAndReplaceTerm":{"anyOf":[{"type":"string"},{"$ref":"#/definitions/ConditionalSearchAndReplaceTerm"}]},"ConditionalSearchAndReplaceTerm":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"search":{},"replace":{}},"required":["search","replace"]},"LastfmClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]}},"required":["apiKey","secret"],"description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using LastFM as a client","default":"client","examples":["client"]},"type":{"type":"string","enum":["lastfm"]}},"required":["data","name","type"]},"ListenBrainzClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/ListenBrainzClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using Listenbrainz as a client","default":"client","examples":["client"]},"type":{"type":"string","enum":["listenbrainz"]}},"required":["data","name","type"]},"ListenBrainzClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]}}} \ No newline at end of file diff --git a/src/backend/common/schema/aio-source.json b/src/backend/common/schema/aio-source.json index a3417b0..d20513f 100644 --- a/src/backend/common/schema/aio-source.json +++ b/src/backend/common/schema/aio-source.json @@ -1,2863 +1 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "ChromecastData": { - "properties": { - "allowUnknownMedia": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "boolean" - } - ], - "default": false, - "description": "Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property", - "title": "allowUnknownMedia" - }, - "blacklistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any application that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "blacklistApps" - }, - "blacklistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "blacklistDevices" - }, - "devices": { - "description": "A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set", - "items": { - "$ref": "#/definitions/ChromecastDeviceInfo" - }, - "title": "devices", - "type": "array" - }, - "forceMediaRecognitionOn": { - "description": "Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive", - "items": { - "type": "string" - }, - "title": "forceMediaRecognitionOn", - "type": "array" - }, - "useAutoDiscovery": { - "description": "Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set", - "title": "useAutoDiscovery", - "type": "boolean" - }, - "useAvahi": { - "default": false, - "description": "Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.", - "title": "useAvahi", - "type": "boolean" - }, - "whitelistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "whitelistApps" - }, - "whitelistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "whitelistDevices" - } - }, - "title": "ChromecastData", - "type": "object" - }, - "ChromecastDeviceInfo": { - "properties": { - "address": { - "description": "The IP address of the device", - "examples": [ - "192.168.0.115" - ], - "title": "address", - "type": "string" - }, - "name": { - "description": "A friendly name to identify this device", - "examples": [ - "MySmartTV" - ], - "title": "name", - "type": "string" - } - }, - "required": [ - "address", - "name" - ], - "title": "ChromecastDeviceInfo", - "type": "object" - }, - "ChromecastSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/ChromecastData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "chromecast" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "ChromecastSourceAIOConfig", - "type": "object" - }, - "CommonSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "CommonSourceOptions", - "type": "object" - }, - "ConditionalSearchAndReplaceTerm": { - "properties": { - "replace": { - "description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace", - "title": "replace", - "type": "string" - }, - "search": { - "anyOf": [ - { - "$ref": "#/definitions/RegExp" - }, - { - "type": "string" - } - ], - "description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression as a string, or an actual RegExp object", - "title": "search" - }, - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "required": [ - "replace", - "search" - ], - "title": "ConditionalSearchAndReplaceTerm", - "type": "object" - }, - "DeezerData": { - "properties": { - "clientId": { - "description": "deezer client id", - "examples": [ - "a89cba1569901a0671d5a9875fed4be1" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "deezer client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 60, - "description": "optional, how long to wait before calling spotify for new tracks (in seconds)", - "examples": [ - 60 - ], - "title": "interval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/deezer/callback", - "description": "deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/deezer/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "DeezerData", - "type": "object" - }, - "DeezerSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/DeezerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "deezer" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "DeezerSourceAIOConfig", - "type": "object" - }, - "JRiverData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "If you have enabled authentication, the password you set", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:52199/MCWS/v1/", - "description": "URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`", - "examples": [ - "http://localhost:52199/MCWS/v1/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "If you have enabled authentication, the username you set", - "title": "username", - "type": "string" - } - }, - "required": [ - "url" - ], - "title": "JRiverData", - "type": "object" - }, - "JRiverSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JRiverData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "jriver" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "JRiverSourceAIOConfig", - "type": "object" - }, - "JellyApiData": { - "properties": { - "apiKey": { - "description": "API Key to authenticate with.\n\nRequired if `password` is not provided.", - "title": "apiKey", - "type": "string" - }, - "devicesAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesAllow" - }, - "devicesBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesBlock" - }, - "password": { - "description": "Password of the username to authenticate for\n\nRequired if `apiKey` is not provided.", - "title": "password", - "type": "string" - }, - "url": { - "description": "HOST:PORT of the Jellyfin server to connect to", - "title": "url", - "type": "string" - }, - "user": { - "description": "The username of the user to authenticate for or track scrobbles for", - "title": "user", - "type": "string" - }, - "usersAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "const": true, - "type": "boolean" - }, - { - "type": "string" - } - ], - "description": "Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users", - "title": "usersAllow" - }, - "usersBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble for these users (case-insensitive)", - "title": "usersBlock" - } - }, - "required": [ - "url", - "user" - ], - "title": "JellyApiData", - "type": "object" - }, - "JellyApiOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "JellyApiOptions", - "type": "object" - }, - "JellyApiSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyApiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/JellyApiOptions", - "title": "options" - }, - "type": { - "enum": [ - "jellyfin" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "options", - "type" - ], - "title": "JellyApiSourceAIOConfig", - "type": "object" - }, - "JellyData": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName1" - ] - ], - "title": "servers" - }, - "users": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "users" - } - }, - "title": "JellyData", - "type": "object" - }, - "JellySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "jellyfin" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "JellySourceAIOConfig", - "type": "object" - }, - "KodiData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "The password set for Remote Control via Web Sever", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:8080/jsonrpc", - "description": "URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`", - "examples": [ - "http://localhost:8080/jsonrpc" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "The username set for Remote Control via Web Sever", - "title": "username", - "type": "string" - } - }, - "required": [ - "password", - "url", - "username" - ], - "title": "KodiData", - "type": "object" - }, - "KodiSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/KodiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "kodi" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "KodiSourceAIOConfig", - "type": "object" - }, - "LastFmSouceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/LastFmSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "lastfm" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "LastFmSouceAIOConfig", - "type": "object" - }, - "LastFmSourceData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastFmSourceData", - "type": "object" - }, - "ListenBrainzSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "listenbrainz" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "ListenBrainzSourceAIOConfig", - "type": "object" - }, - "ListenBrainzSourceData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzSourceData", - "type": "object" - }, - "MPDData": { - "properties": { - "password": { - "description": "Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords", - "title": "password", - "type": "string" - }, - "path": { - "description": "If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory", - "title": "path", - "type": "string" - }, - "url": { - "default": "localhost:6600", - "description": "URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections", - "examples": [ - "localhost:6600" - ], - "title": "url", - "type": "string" - } - }, - "title": "MPDData", - "type": "object" - }, - "MPDSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPDData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/MPDSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mpd" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "options", - "type" - ], - "title": "MPDSourceAIOConfig", - "type": "object" - }, - "MPDSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "MPDSourceOptions", - "type": "object" - }, - "MPRISData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any players that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "blacklist" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "whitelist" - } - }, - "title": "MPRISData", - "type": "object" - }, - "MPRISSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPRISData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mpris" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MPRISSourceAIOConfig", - "type": "object" - }, - "MopidyData": { - "properties": { - "albumBlacklist": { - "default": [ - "Soundcloud" - ], - "description": "Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.", - "examples": [ - [ - "Soundcloud", - "Mixcloud" - ] - ], - "items": { - "type": "string" - }, - "title": "albumBlacklist", - "type": "array" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "uriBlacklist": { - "description": "Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used.", - "items": { - "type": "string" - }, - "title": "uriBlacklist", - "type": "array" - }, - "uriWhitelist": { - "description": "Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list.", - "items": { - "type": "string" - }, - "title": "uriWhitelist", - "type": "array" - }, - "url": { - "default": "ws://localhost:6680/mopidy/ws/", - "description": "URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`", - "examples": [ - "ws://localhost:6680/mopidy/ws/" - ], - "title": "url", - "type": "string" - } - }, - "title": "MopidyData", - "type": "object" - }, - "MopidySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MopidyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mopidy" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MopidySourceAIOConfig", - "type": "object" - }, - "MusikcubeData": { - "properties": { - "device_id": { - "title": "device_id", - "type": "string" - }, - "password": { - "description": "Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password", - "title": "password", - "type": "string" - }, - "url": { - "default": "ws://localhost:7905", - "description": "URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`", - "examples": [ - "ws://localhost:7905" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "MusikcubeData", - "type": "object" - }, - "MusikcubeSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MusikcubeData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "musikcube" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MusikcubeSourceAIOConfig", - "type": "object" - }, - "PlayTransformConfig": { - "properties": { - "compare": { - "properties": { - "candidate": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "candidate" - }, - "existing": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "existing" - } - }, - "title": "compare", - "type": "object" - }, - "postCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "postCompare" - }, - "preCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "preCompare" - } - }, - "title": "PlayTransformConfig", - "type": "object" - }, - "PlayTransformOptions": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformConfig" - }, - { - "properties": { - "log": { - "enum": [ - "all", - false, - true - ], - "title": "log" - } - }, - "type": "object" - } - ], - "title": "PlayTransformOptions" - }, - "PlayTransformParts": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformPartsAtomic" - }, - { - "properties": { - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "type": "object" - } - ], - "title": "PlayTransformParts" - }, - "PlayTransformPartsAtomic": { - "properties": { - "album": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "album", - "type": "array" - }, - "artists": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "artists", - "type": "array" - }, - "title": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "title", - "type": "array" - } - }, - "title": "PlayTransformPartsAtomic", - "type": "object" - }, - "PlayTransformPartsConfig": { - "anyOf": [ - { - "items": { - "$ref": "#/definitions/PlayTransformParts" - }, - "type": "array" - }, - { - "$ref": "#/definitions/PlayTransformParts" - } - ], - "title": "PlayTransformPartsConfig" - }, - "PlexSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "plex" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "PlexSourceAIOConfig", - "type": "object" - }, - "PlexSourceData": { - "properties": { - "libraries": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled", - "examples": [ - [ - "Audio", - "Music" - ] - ], - "title": "libraries" - }, - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName" - ] - ], - "title": "servers" - }, - "user": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "user" - } - }, - "title": "PlexSourceData", - "type": "object" - }, - "RegExp": { - "properties": { - "dotAll": { - "title": "dotAll", - "type": "boolean" - }, - "flags": { - "title": "flags", - "type": "string" - }, - "global": { - "title": "global", - "type": "boolean" - }, - "hasIndices": { - "title": "hasIndices", - "type": "boolean" - }, - "ignoreCase": { - "title": "ignoreCase", - "type": "boolean" - }, - "lastIndex": { - "title": "lastIndex", - "type": "number" - }, - "multiline": { - "title": "multiline", - "type": "boolean" - }, - "source": { - "title": "source", - "type": "string" - }, - "sticky": { - "title": "sticky", - "type": "boolean" - }, - "unicode": { - "title": "unicode", - "type": "boolean" - } - }, - "required": [ - "dotAll", - "flags", - "global", - "hasIndices", - "ignoreCase", - "lastIndex", - "multiline", - "source", - "sticky", - "unicode" - ], - "title": "RegExp", - "type": "object" - }, - "ScrobbleThresholds": { - "properties": { - "duration": { - "default": 240, - "description": "The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.", - "examples": [ - 240 - ], - "title": "duration", - "type": "number" - }, - "percent": { - "default": 50, - "description": "The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.", - "examples": [ - 50 - ], - "title": "percent", - "type": "number" - } - }, - "title": "ScrobbleThresholds", - "type": "object" - }, - "SearchAndReplaceTerm": { - "anyOf": [ - { - "$ref": "#/definitions/ConditionalSearchAndReplaceTerm" - }, - { - "type": "string" - } - ], - "title": "SearchAndReplaceTerm" - }, - "SourceAIOConfig": { - "anyOf": [ - { - "$ref": "#/definitions/ChromecastSourceAIOConfig" - }, - { - "$ref": "#/definitions/DeezerSourceAIOConfig" - }, - { - "$ref": "#/definitions/JellySourceAIOConfig" - }, - { - "$ref": "#/definitions/JellyApiSourceAIOConfig" - }, - { - "$ref": "#/definitions/JRiverSourceAIOConfig" - }, - { - "$ref": "#/definitions/KodiSourceAIOConfig" - }, - { - "$ref": "#/definitions/LastFmSouceAIOConfig" - }, - { - "$ref": "#/definitions/ListenBrainzSourceAIOConfig" - }, - { - "$ref": "#/definitions/MopidySourceAIOConfig" - }, - { - "$ref": "#/definitions/MPDSourceAIOConfig" - }, - { - "$ref": "#/definitions/MPRISSourceAIOConfig" - }, - { - "$ref": "#/definitions/MusikcubeSourceAIOConfig" - }, - { - "$ref": "#/definitions/PlexSourceAIOConfig" - }, - { - "$ref": "#/definitions/SpotifySourceAIOConfig" - }, - { - "$ref": "#/definitions/SubsonicSourceAIOConfig" - }, - { - "$ref": "#/definitions/TautulliSourceAIOConfig" - }, - { - "$ref": "#/definitions/VLCSourceAIOConfig" - }, - { - "$ref": "#/definitions/WebScrobblerSourceAIOConfig" - }, - { - "$ref": "#/definitions/YTMusicSourceAIOConfig" - } - ], - "title": "SourceAIOConfig" - }, - "SourceRetryOptions": { - "properties": { - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - } - }, - "title": "SourceRetryOptions", - "type": "object" - }, - "SpotifySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SpotifySourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "spotify" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "SpotifySourceAIOConfig", - "type": "object" - }, - "SpotifySourceData": { - "properties": { - "clientId": { - "description": "spotify client id", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "spotify client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/callback", - "description": "spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "SpotifySourceData", - "type": "object" - }, - "SubsonicData": { - "properties": { - "ignoreTlsErrors": { - "default": false, - "description": "If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.", - "title": "ignoreTlsErrors", - "type": "boolean" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "legacyAuthentication": { - "default": false, - "description": "Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp", - "title": "legacyAuthentication", - "type": "boolean" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the user to login to the server with", - "examples": [ - "MyPassword" - ], - "title": "password", - "type": "string" - }, - "url": { - "description": "URL of the subsonic media server to query", - "examples": [ - "http://airsonic.local" - ], - "title": "url", - "type": "string" - }, - "user": { - "description": "Username to login to the server with", - "title": "user", - "type": "string" - } - }, - "required": [ - "password", - "url", - "user" - ], - "title": "SubsonicData", - "type": "object" - }, - "SubsonicSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SubsonicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "subsonic" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "SubsonicSourceAIOConfig", - "type": "object" - }, - "TautulliSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "tautulli" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "TautulliSourceAIOConfig", - "type": "object" - }, - "VLCData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the server", - "title": "password", - "type": "string" - }, - "url": { - "default": "localhost:8080", - "description": "URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc", - "examples": [ - "localhost:8080" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "VLCData", - "type": "object" - }, - "VLCSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/VLCData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/VLCSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "vlc" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "VLCSourceAIOConfig", - "type": "object" - }, - "VLCSourceOptions": { - "properties": { - "dumpVlcMetadata": { - "default": false, - "description": "Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.", - "title": "dumpVlcMetadata", - "type": "boolean" - }, - "filenamePatterns": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track", - "title": "filenamePatterns" - }, - "logFilenamePatterns": { - "default": false, - "description": "Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns", - "title": "logFilenamePatterns", - "type": "boolean" - }, - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "VLCSourceOptions", - "type": "object" - }, - "WebScrobblerData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Block scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "youtube" - ] - ], - "title": "blacklist" - }, - "slug": { - "description": "The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used", - "title": "slug", - "type": "string" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only allow scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "mixcloud", - "soundcloud", - "bandcamp" - ] - ], - "title": "whitelist" - } - }, - "title": "WebScrobblerData", - "type": "object" - }, - "WebScrobblerSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/WebScrobblerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "webscrobbler" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "type" - ], - "title": "WebScrobblerSourceAIOConfig", - "type": "object" - }, - "WhenParts": { - "properties": { - "album": { - "title": "album", - "type": "string" - }, - "artists": { - "title": "artists", - "type": "string" - }, - "title": { - "title": "title", - "type": "string" - } - }, - "title": "WhenParts", - "type": "object" - }, - "YTMusicData": { - "properties": { - "authUser": { - "description": "If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included", - "title": "authUser", - "type": [ - "string", - "number" - ] - }, - "cookie": { - "description": "The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.", - "examples": [ - "VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..." - ], - "title": "cookie", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - } - }, - "required": [ - "cookie" - ], - "title": "YTMusicData", - "type": "object" - }, - "YTMusicSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/YTMusicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "allOf": [ - { - "$ref": "#/definitions/CommonSourceOptions" - }, - { - "properties": { - "logAuthUpdateChanges": { - "description": "When true MS will log to DEBUG what parts of the cookie are updated by YTM", - "title": "logAuthUpdateChanges", - "type": "boolean" - } - }, - "type": "object" - } - ], - "title": "options" - }, - "type": { - "enum": [ - "ytmusic" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "YTMusicSourceAIOConfig", - "type": "object" - } - }, - "properties": { - "sourceDefaults": { - "$ref": "#/definitions/SourceRetryOptions", - "title": "sourceDefaults" - }, - "sources": { - "items": { - "$ref": "#/definitions/SourceAIOConfig" - }, - "title": "sources", - "type": "array" - } - }, - "type": "object" -} - +{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/AIOSourceConfig","definitions":{"AIOSourceConfig":{"type":"object","properties":{"sourceDefaults":{"$ref":"#/definitions/SourceRetryOptions"},"sources":{"type":"array","items":{"$ref":"#/definitions/SourceAIOConfig"}}}},"SourceRetryOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]}}},"SourceAIOConfig":{"anyOf":[{"$ref":"#/definitions/SpotifySourceAIOConfig"},{"$ref":"#/definitions/PlexSourceAIOConfig"},{"$ref":"#/definitions/TautulliSourceAIOConfig"},{"$ref":"#/definitions/DeezerSourceAIOConfig"},{"$ref":"#/definitions/SubsonicSourceAIOConfig"},{"$ref":"#/definitions/JellySourceAIOConfig"},{"$ref":"#/definitions/JellyApiSourceAIOConfig"},{"$ref":"#/definitions/LastFmSouceAIOConfig"},{"$ref":"#/definitions/YTMusicSourceAIOConfig"},{"$ref":"#/definitions/MPRISSourceAIOConfig"},{"$ref":"#/definitions/MopidySourceAIOConfig"},{"$ref":"#/definitions/ListenBrainzSourceAIOConfig"},{"$ref":"#/definitions/JRiverSourceAIOConfig"},{"$ref":"#/definitions/KodiSourceAIOConfig"},{"$ref":"#/definitions/WebScrobblerSourceAIOConfig"},{"$ref":"#/definitions/ChromecastSourceAIOConfig"},{"$ref":"#/definitions/MusikcubeSourceAIOConfig"},{"$ref":"#/definitions/MPDSourceAIOConfig"},{"$ref":"#/definitions/VLCSourceAIOConfig"}]},"SpotifySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SpotifySourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["spotify"]}},"required":["data","type"]},"SpotifySourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"clientId":{"type":"string","description":"spotify client id","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"clientSecret":{"type":"string","description":"spotify client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/callback","examples":["http://localhost:9078/callback"]}},"required":["clientId","clientSecret"]},"CommonSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"ScrobbleThresholds":{"type":"object","properties":{"duration":{"type":["number","null"],"description":"The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.","default":240,"examples":[240]},"percent":{"type":["number","null"],"description":"The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.","default":50,"examples":[50]}}},"PlayTransformOptions":{"type":"object","properties":{"log":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["all"]}]},"preCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"compare":{"type":"object","properties":{"candidate":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"existing":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"postCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"PlayTransformPartsConfig":{"anyOf":[{"$ref":"#/definitions/PlayTransformPartsArray%3CSearchAndReplaceTerm%3E"},{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}]},"PlayTransformPartsArray":{"type":"array","items":{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}},"PlayTransformParts":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"title":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"artists":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"album":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}}}},"WhenConditionsConfig":{"$ref":"#/definitions/WhenConditions%3Cstring%3E"},"WhenConditions":{"type":"array","items":{"$ref":"#/definitions/WhenParts%3Cstring%3E"}},"WhenParts":{"$ref":"#/definitions/PlayTransformPartsAtomic%3Cstring%3E"},"PlayTransformPartsAtomic":{"type":"object","properties":{"title":{"type":"string"},"artists":{"type":"string"},"album":{"type":"string"}}},"SearchAndReplaceTerm":{"anyOf":[{"type":"string"},{"$ref":"#/definitions/ConditionalSearchAndReplaceTerm"}]},"ConditionalSearchAndReplaceTerm":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"search":{},"replace":{}},"required":["search","replace"]},"PlexSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["plex"]}},"required":["data","type"]},"PlexSourceData":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"libraries":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled","examples":[["Audio","Music"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName"]]}}},"TautulliSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["tautulli"]}},"required":["data","type"]},"DeezerSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/DeezerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["deezer"]}},"required":["data","type"]},"DeezerData":{"type":"object","properties":{"clientId":{"type":"string","description":"deezer client id","examples":["a89cba1569901a0671d5a9875fed4be1"]},"clientSecret":{"type":"string","description":"deezer client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/deezer/callback","examples":["http://localhost:9078/deezer/callback"]},"interval":{"type":"number","description":"optional, how long to wait before calling spotify for new tracks (in seconds)","default":60,"examples":[60]}},"required":["clientId","clientSecret"]},"SubsonicSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SubsonicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["subsonic"]}},"required":["data","type"]},"SubsonicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the subsonic media server to query","examples":["http://airsonic.local"]},"user":{"type":"string","description":"Username to login to the server with","examples":[["MyUser"]]},"password":{"type":"string","description":"Password for the user to login to the server with","examples":["MyPassword"]},"ignoreTlsErrors":{"type":"boolean","description":"If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.","default":false},"legacyAuthentication":{"type":"boolean","description":"Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp","default":false}},"required":["url","user","password"]},"JellySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["jellyfin"]}},"required":["data","type"]},"JellyData":{"type":"object","properties":{"users":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName1"]]}}},"JellyApiSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyApiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/JellyApiOptions"},"type":{"type":"string","enum":["jellyfin"]}},"required":["data","options","type"]},"JellyApiData":{"type":"object","properties":{"url":{"type":"string","description":"HOST:PORT of the Jellyfin server to connect to"},"user":{"type":"string","description":"The username of the user to authenticate for or track scrobbles for"},"password":{"type":"string","description":"Password of the username to authenticate for\n\nRequired if `apiKey` is not provided."},"apiKey":{"type":"string","description":"API Key to authenticate with.\n\nRequired if `password` is not provided."},"usersAllow":{"anyOf":[{"type":"string"},{"type":"boolean","enum":[true]},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users"},"usersBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble for these users (case-insensitive)"},"devicesAllow":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"},"devicesBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"}},"required":["url","user"]},"JellyApiOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"LastFmSouceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/LastFmSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]},"type":{"type":"string","enum":["lastfm"]}},"required":["data","type"]},"LastFmSourceData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]},"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]}},"required":["apiKey","secret"]},"YTMusicSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/YTMusicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"type":"object","properties":{"logAuthUpdateChanges":{"type":"boolean","description":"When true MS will log to DEBUG what parts of the cookie are updated by YTM"},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"type":{"type":"string","enum":["ytmusic"]}},"required":["data","type"]},"YTMusicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"cookie":{"type":"string","description":"The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.","examples":["VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..."]},"authUser":{"type":["number","string"],"description":"If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included","examples":[[0]]}},"required":["cookie"]},"MPRISSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPRISData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["mpris"]}},"required":["data","type"]},"MPRISData":{"type":"object","properties":{"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any players that START WITH these values, case-insensitive","examples":[["spotify","vlc"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","vlc"]]}}},"MopidySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MopidyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["mopidy"]}},"required":["data","type"]},"MopidyData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`","examples":["ws://localhost:6680/mopidy/ws/"],"default":"ws://localhost:6680/mopidy/ws/"},"uriBlacklist":{"type":"array","items":{"type":"string"},"description":"Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used."},"uriWhitelist":{"type":"array","items":{"type":"string"},"description":"Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list."},"albumBlacklist":{"type":"array","items":{"type":"string"},"description":"Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.","examples":[["Soundcloud","Mixcloud"]],"default":["Soundcloud"]}}},"ListenBrainzSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ListenBrainzSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]},"type":{"type":"string","enum":["listenbrainz"]}},"required":["data","type"]},"ListenBrainzSourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]},"JRiverSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JRiverData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["jriver"]}},"required":["data","type"]},"JRiverData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`","examples":["http://localhost:52199/MCWS/v1/"],"default":"http://localhost:52199/MCWS/v1/"},"username":{"type":"string","description":"If you have enabled authentication, the username you set"},"password":{"type":"string","description":"If you have enabled authentication, the password you set"}},"required":["url"]},"KodiSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/KodiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["kodi"]}},"required":["data","type"]},"KodiData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`","examples":["http://localhost:8080/jsonrpc"],"default":"http://localhost:8080/jsonrpc"},"username":{"type":"string","description":"The username set for Remote Control via Web Sever"},"password":{"type":"string","description":"The password set for Remote Control via Web Sever"}},"required":["url","username","password"]},"WebScrobblerSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/WebScrobblerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["webscrobbler"]}},"required":["type"]},"WebScrobblerData":{"type":"object","properties":{"slug":{"type":["string","null"],"description":"The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used"},"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Block scrobbling from specific WebScrobbler Connectors","examples":[["youtube"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only allow scrobbling from specific WebScrobbler Connectors","examples":[["mixcloud","soundcloud","bandcamp"]]}}},"ChromecastSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ChromecastData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["chromecast"]}},"required":["data","type"]},"ChromecastData":{"type":"object","properties":{"blacklistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"whitelistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"blacklistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any application that START WITH these values, case-insensitive","examples":[["spotify","pandora"]]},"whitelistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","pandora"]]},"useAvahi":{"type":"boolean","description":"Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.","default":false},"useAutoDiscovery":{"type":"boolean","description":"Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set"},"devices":{"type":"array","items":{"$ref":"#/definitions/ChromecastDeviceInfo"},"description":"A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set"},"allowUnknownMedia":{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property","default":false},"forceMediaRecognitionOn":{"type":"array","items":{"type":"string"},"description":"Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive"}}},"ChromecastDeviceInfo":{"type":"object","properties":{"name":{"type":"string","description":"A friendly name to identify this device","examples":["MySmartTV"]},"address":{"type":"string","description":"The IP address of the device","examples":["192.168.0.115"]}},"required":["name","address"]},"MusikcubeSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MusikcubeData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["musikcube"]}},"required":["data","type"]},"MusikcubeData":{"type":"object","properties":{"url":{"type":"string","description":"URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`","examples":["ws://localhost:7905"],"default":"ws://localhost:7905"},"password":{"type":"string","description":"Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password"},"device_id":{"type":"string"}},"required":["password"]},"MPDSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPDData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/MPDSourceOptions"},"type":{"type":"string","enum":["mpd"]}},"required":["data","options","type"]},"MPDData":{"type":"object","properties":{"url":{"type":"string","description":"URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections","examples":["localhost:6600"],"default":"localhost:6600"},"path":{"type":"string","description":"If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory"},"password":{"type":"string","description":"Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords"}}},"MPDSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"VLCSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/VLCData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/VLCSourceOptions"},"type":{"type":"string","enum":["vlc"]}},"required":["data","type"]},"VLCData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc","examples":["localhost:8080"],"default":"localhost:8080"},"password":{"type":"string","description":"Password for the server"}},"required":["password"]},"VLCSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"},"filenamePatterns":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track"},"logFilenamePatterns":{"type":"boolean","description":"Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns","default":false},"dumpVlcMetadata":{"type":"boolean","description":"Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.","default":false}}}}} \ No newline at end of file diff --git a/src/backend/common/schema/aio.json b/src/backend/common/schema/aio.json index d4ad4af..a8d8823 100644 --- a/src/backend/common/schema/aio.json +++ b/src/backend/common/schema/aio.json @@ -1,3877 +1 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "AppriseConfig": { - "properties": { - "host": { - "description": "The URL of the apprise-api server", - "examples": [ - "http://192.168.0.100:8078" - ], - "title": "host", - "type": "string" - }, - "keys": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "If using [Persistent Store Endpoints](https://github.com/caronc/apprise-api?tab=readme-ov-file#persistent-storage-solution) the Configuration ID(s) to send to\n\nNote: If multiple keys are defined then MS will attempt to POST to each one individually", - "title": "keys" - }, - "name": { - "description": "A friendly name used to identify webhook config in logs", - "title": "name", - "type": "string" - }, - "tags": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Optional [tag(s)](https://github.com/caronc/apprise-api?tab=readme-ov-file#tagging) to send in the notification payload", - "title": "tags" - }, - "type": { - "description": "Webhook type. Valid values are:\n\n* gotify\n* ntfy", - "enum": [ - "apprise", - "gotify", - "ntfy" - ], - "examples": [ - "gotify" - ], - "title": "type", - "type": "string" - }, - "urls": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "If using [Stateless Endpoints](https://github.com/caronc/apprise-api?tab=readme-ov-file#stateless-solution) the Apprise config URL(s) to send", - "title": "urls" - } - }, - "required": [ - "host", - "type" - ], - "title": "AppriseConfig", - "type": "object" - }, - "ChromecastData": { - "properties": { - "allowUnknownMedia": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "boolean" - } - ], - "default": false, - "description": "Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property", - "title": "allowUnknownMedia" - }, - "blacklistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any application that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "blacklistApps" - }, - "blacklistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "blacklistDevices" - }, - "devices": { - "description": "A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set", - "items": { - "$ref": "#/definitions/ChromecastDeviceInfo" - }, - "title": "devices", - "type": "array" - }, - "forceMediaRecognitionOn": { - "description": "Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive", - "items": { - "type": "string" - }, - "title": "forceMediaRecognitionOn", - "type": "array" - }, - "useAutoDiscovery": { - "description": "Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set", - "title": "useAutoDiscovery", - "type": "boolean" - }, - "useAvahi": { - "default": false, - "description": "Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.", - "title": "useAvahi", - "type": "boolean" - }, - "whitelistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "whitelistApps" - }, - "whitelistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "whitelistDevices" - } - }, - "title": "ChromecastData", - "type": "object" - }, - "ChromecastDeviceInfo": { - "properties": { - "address": { - "description": "The IP address of the device", - "examples": [ - "192.168.0.115" - ], - "title": "address", - "type": "string" - }, - "name": { - "description": "A friendly name to identify this device", - "examples": [ - "MySmartTV" - ], - "title": "name", - "type": "string" - } - }, - "required": [ - "address", - "name" - ], - "title": "ChromecastDeviceInfo", - "type": "object" - }, - "ChromecastSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/ChromecastData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "chromecast" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "ChromecastSourceAIOConfig", - "type": "object" - }, - "ClientAIOConfig": { - "anyOf": [ - { - "$ref": "#/definitions/LastfmClientAIOConfig" - }, - { - "$ref": "#/definitions/ListenBrainzClientAIOConfig" - }, - { - "$ref": "#/definitions/MalojaClientAIOConfig" - } - ], - "title": "ClientAIOConfig" - }, - "ClientDefaults": { - "properties": { - "checkExistingScrobbles": { - "default": true, - "description": "Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.", - "examples": [ - true - ], - "title": "checkExistingScrobbles", - "type": "boolean" - }, - "deadLetterRetries": { - "default": 1, - "description": "Number of times MS should automatically retry scrobbles in dead letter queue", - "examples": [ - 1 - ], - "title": "deadLetterRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "refreshEnabled": { - "default": true, - "description": "Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history", - "examples": [ - true - ], - "title": "refreshEnabled", - "type": "boolean" - }, - "refreshInitialCount": { - "description": "The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call.", - "title": "refreshInitialCount", - "type": "number" - }, - "refreshMinInterval": { - "default": 5000, - "description": "Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.", - "examples": [ - 5000 - ], - "title": "refreshMinInterval", - "type": "number" - }, - "refreshStaleAfter": { - "default": 60, - "description": "Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.", - "examples": [ - 60 - ], - "title": "refreshStaleAfter", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "verbose": { - "description": "Options used for increasing verbosity of logging in MS (used for debugging)", - "properties": { - "match": { - "$ref": "#/definitions/MatchLoggingOptions", - "title": "match" - } - }, - "title": "verbose", - "type": "object" - } - }, - "title": "ClientDefaults", - "type": "object" - }, - "CommonClientData": { - "title": "CommonClientData", - "type": "object" - }, - "CommonClientOptions": { - "properties": { - "checkExistingScrobbles": { - "default": true, - "description": "Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.", - "examples": [ - true - ], - "title": "checkExistingScrobbles", - "type": "boolean" - }, - "deadLetterRetries": { - "default": 1, - "description": "Number of times MS should automatically retry scrobbles in dead letter queue", - "examples": [ - 1 - ], - "title": "deadLetterRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "refreshEnabled": { - "default": true, - "description": "Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history", - "examples": [ - true - ], - "title": "refreshEnabled", - "type": "boolean" - }, - "refreshInitialCount": { - "description": "The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call.", - "title": "refreshInitialCount", - "type": "number" - }, - "refreshMinInterval": { - "default": 5000, - "description": "Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.", - "examples": [ - 5000 - ], - "title": "refreshMinInterval", - "type": "number" - }, - "refreshStaleAfter": { - "default": 60, - "description": "Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.", - "examples": [ - 60 - ], - "title": "refreshStaleAfter", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "verbose": { - "description": "Options used for increasing verbosity of logging in MS (used for debugging)", - "properties": { - "match": { - "$ref": "#/definitions/MatchLoggingOptions", - "title": "match" - } - }, - "title": "verbose", - "type": "object" - } - }, - "title": "CommonClientOptions", - "type": "object" - }, - "CommonSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "CommonSourceOptions", - "type": "object" - }, - "ConditionalSearchAndReplaceTerm": { - "properties": { - "replace": { - "description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace", - "title": "replace", - "type": "string" - }, - "search": { - "anyOf": [ - { - "$ref": "#/definitions/RegExp" - }, - { - "type": "string" - } - ], - "description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression as a string, or an actual RegExp object", - "title": "search" - }, - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "required": [ - "replace", - "search" - ], - "title": "ConditionalSearchAndReplaceTerm", - "type": "object" - }, - "DeezerData": { - "properties": { - "clientId": { - "description": "deezer client id", - "examples": [ - "a89cba1569901a0671d5a9875fed4be1" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "deezer client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 60, - "description": "optional, how long to wait before calling spotify for new tracks (in seconds)", - "examples": [ - 60 - ], - "title": "interval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/deezer/callback", - "description": "deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/deezer/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "DeezerData", - "type": "object" - }, - "DeezerSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/DeezerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "deezer" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "DeezerSourceAIOConfig", - "type": "object" - }, - "FileLogOptions": { - "properties": { - "frequency": { - "anyOf": [ - { - "enum": [ - "daily", - "hourly" - ], - "type": "string" - }, - { - "type": "number" - } - ], - "default": "'daily'", - "description": "The amount of time a given rolling log file is used. Can be combined with size.\n\nUse `daily` or `hourly` to rotate file every day (or every hour). Existing file within the current day (or hour) will be re-used.\n\nNumerical values will be considered as a number of milliseconds. Using a numerical value will always create a new file upon startup.", - "title": "frequency" - }, - "level": { - "description": "Specify the minimum log level to output to rotating files. If `false` no log files will be created.", - "enum": [ - "debug", - "error", - false, - "fatal", - "info", - "log", - "silent", - "verbose", - "warn" - ], - "title": "level" - }, - "path": { - "default": "'./logs/app.log'", - "description": "The path and filename to use for log files.\n\nIf using rolling files the filename will be appended with `.N` (a number) BEFORE the extension based on rolling status.\n\nMay also be specified using env LOG_PATH or a function that returns a string.\n\nIf path is relative the absolute path will be derived from `logBaseDir` (in `LoggerAppExtras`) which defaults to CWD", - "title": "path", - "type": [ - "string", - "object" - ] - }, - "size": { - "default": "'10MB'", - "description": "The maximum size of a given rolling log file.\n\nCan be combined with frequency. Use k, m and g to express values in KB, MB or GB.\n\nNumerical values will be considered as MB.", - "title": "size", - "type": [ - "string", - "number" - ] - }, - "timestamp": { - "default": "'auto'", - "description": "For rolling log files\n\nWhen\n* value passed to rolling destination is a string (`path` from LogOptions is a string) and\n* `frequency` is defined\n\nThis determines the format of the datetime inserted into the log file name:\n\n* `unix` - unix epoch timestamp in milliseconds\n* `iso` - Full [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) datetime IE '2024-03-07T20:11:34Z'\n* `auto`\n * When frequency is `daily` only inserts date IE YYYY-MM-DD\n * Otherwise inserts full ISO8601 datetime", - "enum": [ - "auto", - "iso", - "unix" - ], - "title": "timestamp", - "type": "string" - } - }, - "title": "FileLogOptions", - "type": "object" - }, - "GotifyConfig": { - "properties": { - "name": { - "description": "A friendly name used to identify webhook config in logs", - "title": "name", - "type": "string" - }, - "priorities": { - "$ref": "#/definitions/PrioritiesConfig", - "description": "Priority of messages\n\n* Info -> 5\n* Warn -> 7\n* Error -> 10", - "title": "priorities" - }, - "token": { - "description": "The token created for this Application in Gotify", - "examples": [ - "AQZI58fA.rfSZbm" - ], - "title": "token", - "type": "string" - }, - "type": { - "description": "Webhook type. Valid values are:\n\n* gotify\n* ntfy", - "enum": [ - "apprise", - "gotify", - "ntfy" - ], - "examples": [ - "gotify" - ], - "title": "type", - "type": "string" - }, - "url": { - "description": "The URL of the Gotify server. Same URL that would be used to reach the Gotify UI", - "examples": [ - "http://192.168.0.100:8078" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "token", - "type", - "url" - ], - "title": "GotifyConfig", - "type": "object" - }, - "JRiverData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "If you have enabled authentication, the password you set", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:52199/MCWS/v1/", - "description": "URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`", - "examples": [ - "http://localhost:52199/MCWS/v1/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "If you have enabled authentication, the username you set", - "title": "username", - "type": "string" - } - }, - "required": [ - "url" - ], - "title": "JRiverData", - "type": "object" - }, - "JRiverSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JRiverData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "jriver" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "JRiverSourceAIOConfig", - "type": "object" - }, - "JellyApiData": { - "properties": { - "apiKey": { - "description": "API Key to authenticate with.\n\nRequired if `password` is not provided.", - "title": "apiKey", - "type": "string" - }, - "devicesAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesAllow" - }, - "devicesBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesBlock" - }, - "password": { - "description": "Password of the username to authenticate for\n\nRequired if `apiKey` is not provided.", - "title": "password", - "type": "string" - }, - "url": { - "description": "HOST:PORT of the Jellyfin server to connect to", - "title": "url", - "type": "string" - }, - "user": { - "description": "The username of the user to authenticate for or track scrobbles for", - "title": "user", - "type": "string" - }, - "usersAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "const": true, - "type": "boolean" - }, - { - "type": "string" - } - ], - "description": "Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users", - "title": "usersAllow" - }, - "usersBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble for these users (case-insensitive)", - "title": "usersBlock" - } - }, - "required": [ - "url", - "user" - ], - "title": "JellyApiData", - "type": "object" - }, - "JellyApiOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "JellyApiOptions", - "type": "object" - }, - "JellyApiSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyApiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/JellyApiOptions", - "title": "options" - }, - "type": { - "enum": [ - "jellyfin" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "options", - "type" - ], - "title": "JellyApiSourceAIOConfig", - "type": "object" - }, - "JellyData": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName1" - ] - ], - "title": "servers" - }, - "users": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "users" - } - }, - "title": "JellyData", - "type": "object" - }, - "JellySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "jellyfin" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "JellySourceAIOConfig", - "type": "object" - }, - "KodiData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "The password set for Remote Control via Web Sever", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:8080/jsonrpc", - "description": "URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`", - "examples": [ - "http://localhost:8080/jsonrpc" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "The username set for Remote Control via Web Sever", - "title": "username", - "type": "string" - } - }, - "required": [ - "password", - "url", - "username" - ], - "title": "KodiData", - "type": "object" - }, - "KodiSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/KodiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "kodi" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "KodiSourceAIOConfig", - "type": "object" - }, - "LastFmSouceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/LastFmSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "lastfm" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "LastFmSouceAIOConfig", - "type": "object" - }, - "LastFmSourceData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastFmSourceData", - "type": "object" - }, - "LastfmClientAIOConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using LastFM as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "allOf": [ - { - "$ref": "#/definitions/CommonClientData" - }, - { - "$ref": "#/definitions/LastfmData" - } - ], - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "lastfm" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "LastfmClientAIOConfig", - "type": "object" - }, - "LastfmData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastfmData", - "type": "object" - }, - "ListenBrainzClientAIOConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using Listenbrainz as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "listenbrainz" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "ListenBrainzClientAIOConfig", - "type": "object" - }, - "ListenBrainzClientData": { - "properties": { - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzClientData", - "type": "object" - }, - "ListenBrainzSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "listenbrainz" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "ListenBrainzSourceAIOConfig", - "type": "object" - }, - "ListenBrainzSourceData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzSourceData", - "type": "object" - }, - "LogLevel": { - "description": "Names of log levels that can be invoked on the logger\n\nFrom lowest to highest:\n\n* `debug`\n* `verbose`\n* `log`\n* `info`\n* `warn`\n* `error`\n* `fatal`\n* `silent` (will never output anything)\n\nWhen used in `LogOptions` specifies the **minimum** level the output should log at.", - "enum": [ - "debug", - "error", - "fatal", - "info", - "log", - "silent", - "verbose", - "warn" - ], - "title": "LogLevel", - "type": "string" - }, - "LogOptions": { - "description": "Configure log levels and file options for an AppLogger.\n\n```ts\nconst infoLogger = loggerApp({\n level: 'info' // console and file will log any levels `info` and above\n});\n\nconst logger = loggerApp({\n console: 'debug', // console will log `debug` and higher\n file: 'warn' // file will log `warn` and higher\n});\n\nconst fileLogger = loggerRollingApp({\n console: 'debug', // console will log `debug` and higher\n file: {\n level: 'warn', // file will log `warn` and higher\n path: '/my/cool/path/output.log', // optionally, output to log file at this path\n frequency: 'hourly', // optionally, rotate hourly\n }\n});\n```", - "properties": { - "console": { - "$ref": "#/definitions/LogLevel", - "description": "Specify the minimum log level streamed to the console (or docker container)", - "title": "console" - }, - "file": { - "anyOf": [ - { - "$ref": "#/definitions/FileLogOptions" - }, - { - "enum": [ - "debug", - "error", - false, - "fatal", - "info", - "log", - "silent", - "verbose", - "warn" - ] - } - ], - "description": "Specify the minimum log level to output to rotating files or file output options. If `false` no log files will be created.", - "title": "file" - }, - "level": { - "$ref": "#/definitions/LogLevel", - "default": "'info'", - "description": "Specify the minimum log level for all log outputs without their own level specified.\n\nDefaults to env `LOG_LEVEL` or `info` if not specified.", - "title": "level" - } - }, - "title": "LogOptions", - "type": "object" - }, - "MPDData": { - "properties": { - "password": { - "description": "Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords", - "title": "password", - "type": "string" - }, - "path": { - "description": "If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory", - "title": "path", - "type": "string" - }, - "url": { - "default": "localhost:6600", - "description": "URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections", - "examples": [ - "localhost:6600" - ], - "title": "url", - "type": "string" - } - }, - "title": "MPDData", - "type": "object" - }, - "MPDSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPDData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/MPDSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mpd" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "options", - "type" - ], - "title": "MPDSourceAIOConfig", - "type": "object" - }, - "MPDSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "MPDSourceOptions", - "type": "object" - }, - "MPRISData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any players that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "blacklist" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "whitelist" - } - }, - "title": "MPRISData", - "type": "object" - }, - "MPRISSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPRISData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mpris" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MPRISSourceAIOConfig", - "type": "object" - }, - "MalojaClientAIOConfig": { - "properties": { - "data": { - "$ref": "#/definitions/MalojaClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - }, - "type": { - "enum": [ - "maloja" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "name", - "type" - ], - "title": "MalojaClientAIOConfig", - "type": "object" - }, - "MalojaClientData": { - "properties": { - "apiKey": { - "description": "API Key for Maloja server", - "examples": [ - "myApiKey" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "url": { - "description": "URL for maloja server", - "examples": [ - "http://localhost:42010" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "apiKey", - "url" - ], - "title": "MalojaClientData", - "type": "object" - }, - "MatchLoggingOptions": { - "description": "Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging.", - "properties": { - "confidenceBreakdown": { - "default": false, - "description": "Include confidence breakdowns in track match logging, if applicable", - "examples": [ - false - ], - "title": "confidenceBreakdown", - "type": "boolean" - }, - "onMatch": { - "default": false, - "description": "Log to DEBUG when a new track DOES match an existing scrobble", - "examples": [ - false - ], - "title": "onMatch", - "type": "boolean" - }, - "onNoMatch": { - "default": false, - "description": "Log to DEBUG when a new track does NOT match an existing scrobble", - "examples": [ - false - ], - "title": "onNoMatch", - "type": "boolean" - } - }, - "title": "MatchLoggingOptions", - "type": "object" - }, - "MopidyData": { - "properties": { - "albumBlacklist": { - "default": [ - "Soundcloud" - ], - "description": "Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.", - "examples": [ - [ - "Soundcloud", - "Mixcloud" - ] - ], - "items": { - "type": "string" - }, - "title": "albumBlacklist", - "type": "array" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "uriBlacklist": { - "description": "Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used.", - "items": { - "type": "string" - }, - "title": "uriBlacklist", - "type": "array" - }, - "uriWhitelist": { - "description": "Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list.", - "items": { - "type": "string" - }, - "title": "uriWhitelist", - "type": "array" - }, - "url": { - "default": "ws://localhost:6680/mopidy/ws/", - "description": "URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`", - "examples": [ - "ws://localhost:6680/mopidy/ws/" - ], - "title": "url", - "type": "string" - } - }, - "title": "MopidyData", - "type": "object" - }, - "MopidySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MopidyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "mopidy" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MopidySourceAIOConfig", - "type": "object" - }, - "MusikcubeData": { - "properties": { - "device_id": { - "title": "device_id", - "type": "string" - }, - "password": { - "description": "Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password", - "title": "password", - "type": "string" - }, - "url": { - "default": "ws://localhost:7905", - "description": "URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`", - "examples": [ - "ws://localhost:7905" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "MusikcubeData", - "type": "object" - }, - "MusikcubeSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MusikcubeData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "musikcube" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "MusikcubeSourceAIOConfig", - "type": "object" - }, - "NtfyConfig": { - "properties": { - "name": { - "description": "A friendly name used to identify webhook config in logs", - "title": "name", - "type": "string" - }, - "password": { - "description": "Required if topic is protected", - "title": "password", - "type": "string" - }, - "priorities": { - "$ref": "#/definitions/PrioritiesConfig", - "description": "Priority of messages\n\n* Info -> 3\n* Warn -> 4\n* Error -> 5", - "title": "priorities" - }, - "topic": { - "description": "The topic mutli-scrobbler should POST to", - "title": "topic", - "type": "string" - }, - "type": { - "description": "Webhook type. Valid values are:\n\n* gotify\n* ntfy", - "enum": [ - "apprise", - "gotify", - "ntfy" - ], - "examples": [ - "gotify" - ], - "title": "type", - "type": "string" - }, - "url": { - "description": "The URL of the Ntfy server", - "examples": [ - "http://192.168.0.100:8078" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Required if topic is protected", - "title": "username", - "type": "string" - } - }, - "required": [ - "topic", - "type", - "url" - ], - "title": "NtfyConfig", - "type": "object" - }, - "PlayTransformConfig": { - "properties": { - "compare": { - "properties": { - "candidate": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "candidate" - }, - "existing": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "existing" - } - }, - "title": "compare", - "type": "object" - }, - "postCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "postCompare" - }, - "preCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "preCompare" - } - }, - "title": "PlayTransformConfig", - "type": "object" - }, - "PlayTransformOptions": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformConfig" - }, - { - "properties": { - "log": { - "enum": [ - "all", - false, - true - ], - "title": "log" - } - }, - "type": "object" - } - ], - "title": "PlayTransformOptions" - }, - "PlayTransformParts": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformPartsAtomic" - }, - { - "properties": { - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "type": "object" - } - ], - "title": "PlayTransformParts" - }, - "PlayTransformPartsAtomic": { - "properties": { - "album": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "album", - "type": "array" - }, - "artists": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "artists", - "type": "array" - }, - "title": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "title", - "type": "array" - } - }, - "title": "PlayTransformPartsAtomic", - "type": "object" - }, - "PlayTransformPartsConfig": { - "anyOf": [ - { - "items": { - "$ref": "#/definitions/PlayTransformParts" - }, - "type": "array" - }, - { - "$ref": "#/definitions/PlayTransformParts" - } - ], - "title": "PlayTransformPartsConfig" - }, - "PlexSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "plex" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "PlexSourceAIOConfig", - "type": "object" - }, - "PlexSourceData": { - "properties": { - "libraries": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled", - "examples": [ - [ - "Audio", - "Music" - ] - ], - "title": "libraries" - }, - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName" - ] - ], - "title": "servers" - }, - "user": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "user" - } - }, - "title": "PlexSourceData", - "type": "object" - }, - "PrioritiesConfig": { - "properties": { - "error": { - "examples": [ - 10 - ], - "title": "error", - "type": "number" - }, - "info": { - "examples": [ - 5 - ], - "title": "info", - "type": "number" - }, - "warn": { - "examples": [ - 7 - ], - "title": "warn", - "type": "number" - } - }, - "required": [ - "error", - "info", - "warn" - ], - "title": "PrioritiesConfig", - "type": "object" - }, - "RegExp": { - "properties": { - "dotAll": { - "title": "dotAll", - "type": "boolean" - }, - "flags": { - "title": "flags", - "type": "string" - }, - "global": { - "title": "global", - "type": "boolean" - }, - "hasIndices": { - "title": "hasIndices", - "type": "boolean" - }, - "ignoreCase": { - "title": "ignoreCase", - "type": "boolean" - }, - "lastIndex": { - "title": "lastIndex", - "type": "number" - }, - "multiline": { - "title": "multiline", - "type": "boolean" - }, - "source": { - "title": "source", - "type": "string" - }, - "sticky": { - "title": "sticky", - "type": "boolean" - }, - "unicode": { - "title": "unicode", - "type": "boolean" - } - }, - "required": [ - "dotAll", - "flags", - "global", - "hasIndices", - "ignoreCase", - "lastIndex", - "multiline", - "source", - "sticky", - "unicode" - ], - "title": "RegExp", - "type": "object" - }, - "ScrobbleThresholds": { - "properties": { - "duration": { - "default": 240, - "description": "The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.", - "examples": [ - 240 - ], - "title": "duration", - "type": "number" - }, - "percent": { - "default": 50, - "description": "The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.", - "examples": [ - 50 - ], - "title": "percent", - "type": "number" - } - }, - "title": "ScrobbleThresholds", - "type": "object" - }, - "SearchAndReplaceTerm": { - "anyOf": [ - { - "$ref": "#/definitions/ConditionalSearchAndReplaceTerm" - }, - { - "type": "string" - } - ], - "title": "SearchAndReplaceTerm" - }, - "SourceAIOConfig": { - "anyOf": [ - { - "$ref": "#/definitions/ChromecastSourceAIOConfig" - }, - { - "$ref": "#/definitions/DeezerSourceAIOConfig" - }, - { - "$ref": "#/definitions/JellySourceAIOConfig" - }, - { - "$ref": "#/definitions/JellyApiSourceAIOConfig" - }, - { - "$ref": "#/definitions/JRiverSourceAIOConfig" - }, - { - "$ref": "#/definitions/KodiSourceAIOConfig" - }, - { - "$ref": "#/definitions/LastFmSouceAIOConfig" - }, - { - "$ref": "#/definitions/ListenBrainzSourceAIOConfig" - }, - { - "$ref": "#/definitions/MopidySourceAIOConfig" - }, - { - "$ref": "#/definitions/MPDSourceAIOConfig" - }, - { - "$ref": "#/definitions/MPRISSourceAIOConfig" - }, - { - "$ref": "#/definitions/MusikcubeSourceAIOConfig" - }, - { - "$ref": "#/definitions/PlexSourceAIOConfig" - }, - { - "$ref": "#/definitions/SpotifySourceAIOConfig" - }, - { - "$ref": "#/definitions/SubsonicSourceAIOConfig" - }, - { - "$ref": "#/definitions/TautulliSourceAIOConfig" - }, - { - "$ref": "#/definitions/VLCSourceAIOConfig" - }, - { - "$ref": "#/definitions/WebScrobblerSourceAIOConfig" - }, - { - "$ref": "#/definitions/YTMusicSourceAIOConfig" - } - ], - "title": "SourceAIOConfig" - }, - "SourceDefaults": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "SourceDefaults", - "type": "object" - }, - "SpotifySourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SpotifySourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "spotify" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "SpotifySourceAIOConfig", - "type": "object" - }, - "SpotifySourceData": { - "properties": { - "clientId": { - "description": "spotify client id", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "spotify client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/callback", - "description": "spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "SpotifySourceData", - "type": "object" - }, - "SubsonicData": { - "properties": { - "ignoreTlsErrors": { - "default": false, - "description": "If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.", - "title": "ignoreTlsErrors", - "type": "boolean" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "legacyAuthentication": { - "default": false, - "description": "Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp", - "title": "legacyAuthentication", - "type": "boolean" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the user to login to the server with", - "examples": [ - "MyPassword" - ], - "title": "password", - "type": "string" - }, - "url": { - "description": "URL of the subsonic media server to query", - "examples": [ - "http://airsonic.local" - ], - "title": "url", - "type": "string" - }, - "user": { - "description": "Username to login to the server with", - "title": "user", - "type": "string" - } - }, - "required": [ - "password", - "url", - "user" - ], - "title": "SubsonicData", - "type": "object" - }, - "SubsonicSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SubsonicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "subsonic" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "SubsonicSourceAIOConfig", - "type": "object" - }, - "TautulliSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "tautulli" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "TautulliSourceAIOConfig", - "type": "object" - }, - "VLCData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the server", - "title": "password", - "type": "string" - }, - "url": { - "default": "localhost:8080", - "description": "URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc", - "examples": [ - "localhost:8080" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "VLCData", - "type": "object" - }, - "VLCSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/VLCData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/VLCSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "vlc" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "VLCSourceAIOConfig", - "type": "object" - }, - "VLCSourceOptions": { - "properties": { - "dumpVlcMetadata": { - "default": false, - "description": "Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.", - "title": "dumpVlcMetadata", - "type": "boolean" - }, - "filenamePatterns": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track", - "title": "filenamePatterns" - }, - "logFilenamePatterns": { - "default": false, - "description": "Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns", - "title": "logFilenamePatterns", - "type": "boolean" - }, - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "VLCSourceOptions", - "type": "object" - }, - "WebScrobblerData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Block scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "youtube" - ] - ], - "title": "blacklist" - }, - "slug": { - "description": "The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used", - "title": "slug", - "type": "string" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only allow scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "mixcloud", - "soundcloud", - "bandcamp" - ] - ], - "title": "whitelist" - } - }, - "title": "WebScrobblerData", - "type": "object" - }, - "WebScrobblerSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/WebScrobblerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - }, - "type": { - "enum": [ - "webscrobbler" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "type" - ], - "title": "WebScrobblerSourceAIOConfig", - "type": "object" - }, - "WebhookConfig": { - "anyOf": [ - { - "$ref": "#/definitions/GotifyConfig" - }, - { - "$ref": "#/definitions/NtfyConfig" - }, - { - "$ref": "#/definitions/AppriseConfig" - } - ], - "title": "WebhookConfig" - }, - "WhenParts": { - "properties": { - "album": { - "title": "album", - "type": "string" - }, - "artists": { - "title": "artists", - "type": "string" - }, - "title": { - "title": "title", - "type": "string" - } - }, - "title": "WhenParts", - "type": "object" - }, - "YTMusicData": { - "properties": { - "authUser": { - "description": "If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included", - "title": "authUser", - "type": [ - "string", - "number" - ] - }, - "cookie": { - "description": "The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.", - "examples": [ - "VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..." - ], - "title": "cookie", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - } - }, - "required": [ - "cookie" - ], - "title": "YTMusicData", - "type": "object" - }, - "YTMusicSourceAIOConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/YTMusicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "allOf": [ - { - "$ref": "#/definitions/CommonSourceOptions" - }, - { - "properties": { - "logAuthUpdateChanges": { - "description": "When true MS will log to DEBUG what parts of the cookie are updated by YTM", - "title": "logAuthUpdateChanges", - "type": "boolean" - } - }, - "type": "object" - } - ], - "title": "options" - }, - "type": { - "enum": [ - "ytmusic" - ], - "title": "type", - "type": "string" - } - }, - "required": [ - "data", - "type" - ], - "title": "YTMusicSourceAIOConfig", - "type": "object" - } - }, - "properties": { - "baseUrl": { - "default": "http://localhost", - "description": "Set the Base URL the application should assume the UI is served from.\n\nThis will affect how default redirect URLs are generated (spotify, lastfm, deezer) and some logging messages.\n\nIt will NOT set the actual interface/IP that the application is listening on.\n\nThis can also be set using the BASE_URL environmental variable.", - "examples": [ - "http://localhost", - "http://192.168.0.101", - "https://ms.myDomain.tld" - ], - "title": "baseUrl", - "type": "string" - }, - "clientDefaults": { - "$ref": "#/definitions/ClientDefaults", - "title": "clientDefaults" - }, - "clients": { - "items": { - "$ref": "#/definitions/ClientAIOConfig" - }, - "title": "clients", - "type": "array" - }, - "debugMode": { - "default": false, - "description": "Enables ALL relevant logging and debug options for all sources/clients, when none are defined.\n\nThis is a convenience shortcut for enabling all output needed to troubleshoot an issue and does not need to be on for normal operation.\n\nIt can also be enabled with the environmental variable DEBUG_MODE=true", - "examples": [ - false - ], - "title": "debugMode", - "type": "boolean" - }, - "disableWeb": { - "description": "Disable web server from running/listening on port.\n\nThis will also make any ingress sources (Plex, Jellyfin, Tautulli, etc...) unusable", - "title": "disableWeb", - "type": "boolean" - }, - "logging": { - "$ref": "#/definitions/LogOptions", - "title": "logging" - }, - "port": { - "default": 9078, - "description": "Set the port the multi-scrobbler UI will be served from", - "examples": [ - 9078 - ], - "title": "port", - "type": "number" - }, - "sourceDefaults": { - "$ref": "#/definitions/SourceDefaults", - "title": "sourceDefaults" - }, - "sources": { - "items": { - "$ref": "#/definitions/SourceAIOConfig" - }, - "title": "sources", - "type": "array" - }, - "webhooks": { - "items": { - "$ref": "#/definitions/WebhookConfig" - }, - "title": "webhooks", - "type": "array" - } - }, - "type": "object" -} - +{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/AIOConfig","definitions":{"AIOConfig":{"type":"object","properties":{"sourceDefaults":{"$ref":"#/definitions/SourceDefaults"},"clientDefaults":{"$ref":"#/definitions/ClientDefaults"},"sources":{"type":"array","items":{"$ref":"#/definitions/SourceAIOConfig"}},"clients":{"type":"array","items":{"$ref":"#/definitions/ClientAIOConfig"}},"webhooks":{"type":"array","items":{"$ref":"#/definitions/WebhookConfig"}},"port":{"type":"number","description":"Set the port the multi-scrobbler UI will be served from","default":9078,"examples":[9078]},"baseUrl":{"type":"string","description":"Set the Base URL the application should assume the UI is served from.\n\nThis will affect how default redirect URLs are generated (spotify, lastfm, deezer) and some logging messages.\n\nIt will NOT set the actual interface/IP that the application is listening on.\n\nThis can also be set using the BASE_URL environmental variable.","default":"http://localhost","examples":["http://localhost","http://192.168.0.101","https://ms.myDomain.tld"]},"logging":{"$ref":"#/definitions/LogOptions"},"disableWeb":{"type":"boolean","description":"Disable web server from running/listening on port.\n\nThis will also make any ingress sources (Plex, Jellyfin, Tautulli, etc...) unusable"},"debugMode":{"type":"boolean","description":"Enables ALL relevant logging and debug options for all sources/clients, when none are defined.\n\nThis is a convenience shortcut for enabling all output needed to troubleshoot an issue and does not need to be on for normal operation.\n\nIt can also be enabled with the environmental variable DEBUG_MODE=true","default":false,"examples":[false]}}},"SourceDefaults":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"ScrobbleThresholds":{"type":"object","properties":{"duration":{"type":["number","null"],"description":"The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.","default":240,"examples":[240]},"percent":{"type":["number","null"],"description":"The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.","default":50,"examples":[50]}}},"PlayTransformOptions":{"type":"object","properties":{"log":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["all"]}]},"preCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"compare":{"type":"object","properties":{"candidate":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"existing":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"postCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"PlayTransformPartsConfig":{"anyOf":[{"$ref":"#/definitions/PlayTransformPartsArray%3CSearchAndReplaceTerm%3E"},{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}]},"PlayTransformPartsArray":{"type":"array","items":{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}},"PlayTransformParts":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"title":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"artists":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"album":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}}}},"WhenConditionsConfig":{"$ref":"#/definitions/WhenConditions%3Cstring%3E"},"WhenConditions":{"type":"array","items":{"$ref":"#/definitions/WhenParts%3Cstring%3E"}},"WhenParts":{"$ref":"#/definitions/PlayTransformPartsAtomic%3Cstring%3E"},"PlayTransformPartsAtomic":{"type":"object","properties":{"title":{"type":"string"},"artists":{"type":"string"},"album":{"type":"string"}}},"SearchAndReplaceTerm":{"anyOf":[{"type":"string"},{"$ref":"#/definitions/ConditionalSearchAndReplaceTerm"}]},"ConditionalSearchAndReplaceTerm":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"search":{},"replace":{}},"required":["search","replace"]},"ClientDefaults":{"type":"object","properties":{"refreshEnabled":{"type":"boolean","description":"Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history","default":true,"examples":[true]},"refreshStaleAfter":{"type":"number","description":"Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.","examples":[60],"default":60},"refreshMinInterval":{"type":"number","description":"Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.","default":5000,"examples":[5000]},"refreshInitialCount":{"type":"number","description":"The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call."},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"checkExistingScrobbles":{"type":"boolean","description":"Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.","default":true,"examples":[true]},"verbose":{"type":"object","properties":{"match":{"$ref":"#/definitions/MatchLoggingOptions"}},"description":"Options used for increasing verbosity of logging in MS (used for debugging)"},"deadLetterRetries":{"type":"number","description":"Number of times MS should automatically retry scrobbles in dead letter queue","default":1,"examples":[1]},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"MatchLoggingOptions":{"type":"object","properties":{"onNoMatch":{"type":"boolean","description":"Log to DEBUG when a new track does NOT match an existing scrobble","default":false,"examples":[false]},"onMatch":{"type":"boolean","description":"Log to DEBUG when a new track DOES match an existing scrobble","default":false,"examples":[false]},"confidenceBreakdown":{"type":"boolean","description":"Include confidence breakdowns in track match logging, if applicable","default":false,"examples":[false]}},"description":"Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging."},"SourceAIOConfig":{"anyOf":[{"$ref":"#/definitions/SpotifySourceAIOConfig"},{"$ref":"#/definitions/PlexSourceAIOConfig"},{"$ref":"#/definitions/TautulliSourceAIOConfig"},{"$ref":"#/definitions/DeezerSourceAIOConfig"},{"$ref":"#/definitions/SubsonicSourceAIOConfig"},{"$ref":"#/definitions/JellySourceAIOConfig"},{"$ref":"#/definitions/JellyApiSourceAIOConfig"},{"$ref":"#/definitions/LastFmSouceAIOConfig"},{"$ref":"#/definitions/YTMusicSourceAIOConfig"},{"$ref":"#/definitions/MPRISSourceAIOConfig"},{"$ref":"#/definitions/MopidySourceAIOConfig"},{"$ref":"#/definitions/ListenBrainzSourceAIOConfig"},{"$ref":"#/definitions/JRiverSourceAIOConfig"},{"$ref":"#/definitions/KodiSourceAIOConfig"},{"$ref":"#/definitions/WebScrobblerSourceAIOConfig"},{"$ref":"#/definitions/ChromecastSourceAIOConfig"},{"$ref":"#/definitions/MusikcubeSourceAIOConfig"},{"$ref":"#/definitions/MPDSourceAIOConfig"},{"$ref":"#/definitions/VLCSourceAIOConfig"}]},"SpotifySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SpotifySourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["spotify"]}},"required":["data","type"]},"SpotifySourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"clientId":{"type":"string","description":"spotify client id","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"clientSecret":{"type":"string","description":"spotify client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/callback","examples":["http://localhost:9078/callback"]}},"required":["clientId","clientSecret"]},"CommonSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"PlexSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["plex"]}},"required":["data","type"]},"PlexSourceData":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"libraries":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled","examples":[["Audio","Music"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName"]]}}},"TautulliSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["tautulli"]}},"required":["data","type"]},"DeezerSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/DeezerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["deezer"]}},"required":["data","type"]},"DeezerData":{"type":"object","properties":{"clientId":{"type":"string","description":"deezer client id","examples":["a89cba1569901a0671d5a9875fed4be1"]},"clientSecret":{"type":"string","description":"deezer client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/deezer/callback","examples":["http://localhost:9078/deezer/callback"]},"interval":{"type":"number","description":"optional, how long to wait before calling spotify for new tracks (in seconds)","default":60,"examples":[60]}},"required":["clientId","clientSecret"]},"SubsonicSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SubsonicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["subsonic"]}},"required":["data","type"]},"SubsonicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the subsonic media server to query","examples":["http://airsonic.local"]},"user":{"type":"string","description":"Username to login to the server with","examples":[["MyUser"]]},"password":{"type":"string","description":"Password for the user to login to the server with","examples":["MyPassword"]},"ignoreTlsErrors":{"type":"boolean","description":"If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.","default":false},"legacyAuthentication":{"type":"boolean","description":"Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp","default":false}},"required":["url","user","password"]},"JellySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["jellyfin"]}},"required":["data","type"]},"JellyData":{"type":"object","properties":{"users":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName1"]]}}},"JellyApiSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyApiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/JellyApiOptions"},"type":{"type":"string","enum":["jellyfin"]}},"required":["data","options","type"]},"JellyApiData":{"type":"object","properties":{"url":{"type":"string","description":"HOST:PORT of the Jellyfin server to connect to"},"user":{"type":"string","description":"The username of the user to authenticate for or track scrobbles for"},"password":{"type":"string","description":"Password of the username to authenticate for\n\nRequired if `apiKey` is not provided."},"apiKey":{"type":"string","description":"API Key to authenticate with.\n\nRequired if `password` is not provided."},"usersAllow":{"anyOf":[{"type":"string"},{"type":"boolean","enum":[true]},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users"},"usersBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble for these users (case-insensitive)"},"devicesAllow":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"},"devicesBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"}},"required":["url","user"]},"JellyApiOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"LastFmSouceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/LastFmSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]},"type":{"type":"string","enum":["lastfm"]}},"required":["data","type"]},"LastFmSourceData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]},"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]}},"required":["apiKey","secret"]},"YTMusicSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/YTMusicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"type":"object","properties":{"logAuthUpdateChanges":{"type":"boolean","description":"When true MS will log to DEBUG what parts of the cookie are updated by YTM"},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"type":{"type":"string","enum":["ytmusic"]}},"required":["data","type"]},"YTMusicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"cookie":{"type":"string","description":"The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.","examples":["VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..."]},"authUser":{"type":["number","string"],"description":"If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included","examples":[[0]]}},"required":["cookie"]},"MPRISSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPRISData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["mpris"]}},"required":["data","type"]},"MPRISData":{"type":"object","properties":{"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any players that START WITH these values, case-insensitive","examples":[["spotify","vlc"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","vlc"]]}}},"MopidySourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MopidyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["mopidy"]}},"required":["data","type"]},"MopidyData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`","examples":["ws://localhost:6680/mopidy/ws/"],"default":"ws://localhost:6680/mopidy/ws/"},"uriBlacklist":{"type":"array","items":{"type":"string"},"description":"Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used."},"uriWhitelist":{"type":"array","items":{"type":"string"},"description":"Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list."},"albumBlacklist":{"type":"array","items":{"type":"string"},"description":"Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.","examples":[["Soundcloud","Mixcloud"]],"default":["Soundcloud"]}}},"ListenBrainzSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ListenBrainzSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]},"type":{"type":"string","enum":["listenbrainz"]}},"required":["data","type"]},"ListenBrainzSourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]},"JRiverSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JRiverData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["jriver"]}},"required":["data","type"]},"JRiverData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`","examples":["http://localhost:52199/MCWS/v1/"],"default":"http://localhost:52199/MCWS/v1/"},"username":{"type":"string","description":"If you have enabled authentication, the username you set"},"password":{"type":"string","description":"If you have enabled authentication, the password you set"}},"required":["url"]},"KodiSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/KodiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["kodi"]}},"required":["data","type"]},"KodiData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`","examples":["http://localhost:8080/jsonrpc"],"default":"http://localhost:8080/jsonrpc"},"username":{"type":"string","description":"The username set for Remote Control via Web Sever"},"password":{"type":"string","description":"The password set for Remote Control via Web Sever"}},"required":["url","username","password"]},"WebScrobblerSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/WebScrobblerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["webscrobbler"]}},"required":["type"]},"WebScrobblerData":{"type":"object","properties":{"slug":{"type":["string","null"],"description":"The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used"},"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Block scrobbling from specific WebScrobbler Connectors","examples":[["youtube"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only allow scrobbling from specific WebScrobbler Connectors","examples":[["mixcloud","soundcloud","bandcamp"]]}}},"ChromecastSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ChromecastData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["chromecast"]}},"required":["data","type"]},"ChromecastData":{"type":"object","properties":{"blacklistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"whitelistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"blacklistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any application that START WITH these values, case-insensitive","examples":[["spotify","pandora"]]},"whitelistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","pandora"]]},"useAvahi":{"type":"boolean","description":"Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.","default":false},"useAutoDiscovery":{"type":"boolean","description":"Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set"},"devices":{"type":"array","items":{"$ref":"#/definitions/ChromecastDeviceInfo"},"description":"A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set"},"allowUnknownMedia":{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property","default":false},"forceMediaRecognitionOn":{"type":"array","items":{"type":"string"},"description":"Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive"}}},"ChromecastDeviceInfo":{"type":"object","properties":{"name":{"type":"string","description":"A friendly name to identify this device","examples":["MySmartTV"]},"address":{"type":"string","description":"The IP address of the device","examples":["192.168.0.115"]}},"required":["name","address"]},"MusikcubeSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MusikcubeData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"type":{"type":"string","enum":["musikcube"]}},"required":["data","type"]},"MusikcubeData":{"type":"object","properties":{"url":{"type":"string","description":"URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`","examples":["ws://localhost:7905"],"default":"ws://localhost:7905"},"password":{"type":"string","description":"Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password"},"device_id":{"type":"string"}},"required":["password"]},"MPDSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPDData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/MPDSourceOptions"},"type":{"type":"string","enum":["mpd"]}},"required":["data","options","type"]},"MPDData":{"type":"object","properties":{"url":{"type":"string","description":"URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections","examples":["localhost:6600"],"default":"localhost:6600"},"path":{"type":"string","description":"If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory"},"password":{"type":"string","description":"Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords"}}},"MPDSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"VLCSourceAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/VLCData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/VLCSourceOptions"},"type":{"type":"string","enum":["vlc"]}},"required":["data","type"]},"VLCData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc","examples":["localhost:8080"],"default":"localhost:8080"},"password":{"type":"string","description":"Password for the server"}},"required":["password"]},"VLCSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"},"filenamePatterns":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track"},"logFilenamePatterns":{"type":"boolean","description":"Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns","default":false},"dumpVlcMetadata":{"type":"boolean","description":"Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.","default":false}}},"ClientAIOConfig":{"anyOf":[{"$ref":"#/definitions/MalojaClientAIOConfig"},{"$ref":"#/definitions/LastfmClientAIOConfig"},{"$ref":"#/definitions/ListenBrainzClientAIOConfig"}]},"MalojaClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/MalojaClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"type":{"type":"string","enum":["maloja"]}},"required":["data","name","type"]},"MalojaClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for maloja server","examples":["http://localhost:42010"]},"apiKey":{"type":"string","description":"API Key for Maloja server","examples":["myApiKey"]}},"required":["url","apiKey"]},"CommonClientOptions":{"type":"object","properties":{"refreshEnabled":{"type":"boolean","description":"Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history","default":true,"examples":[true]},"refreshStaleAfter":{"type":"number","description":"Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.","examples":[60],"default":60},"refreshMinInterval":{"type":"number","description":"Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.","default":5000,"examples":[5000]},"refreshInitialCount":{"type":"number","description":"The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call."},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"checkExistingScrobbles":{"type":"boolean","description":"Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.","default":true,"examples":[true]},"verbose":{"type":"object","properties":{"match":{"$ref":"#/definitions/MatchLoggingOptions"}},"description":"Options used for increasing verbosity of logging in MS (used for debugging)"},"deadLetterRetries":{"type":"number","description":"Number of times MS should automatically retry scrobbles in dead letter queue","default":1,"examples":[1]},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"LastfmClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]}},"required":["apiKey","secret"],"description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using LastFM as a client","default":"client","examples":["client"]},"type":{"type":"string","enum":["lastfm"]}},"required":["data","name","type"]},"ListenBrainzClientAIOConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/ListenBrainzClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using Listenbrainz as a client","default":"client","examples":["client"]},"type":{"type":"string","enum":["listenbrainz"]}},"required":["data","name","type"]},"ListenBrainzClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]},"WebhookConfig":{"anyOf":[{"$ref":"#/definitions/GotifyConfig"},{"$ref":"#/definitions/NtfyConfig"},{"$ref":"#/definitions/AppriseConfig"}]},"GotifyConfig":{"type":"object","properties":{"type":{"type":"string","enum":["gotify","ntfy","apprise"],"description":"Webhook type. Valid values are:\n\n* gotify\n* ntfy","examples":["gotify"]},"name":{"type":"string","description":"A friendly name used to identify webhook config in logs"},"url":{"type":"string","description":"The URL of the Gotify server. Same URL that would be used to reach the Gotify UI","examples":["http://192.168.0.100:8078"]},"token":{"type":"string","description":"The token created for this Application in Gotify","examples":["AQZI58fA.rfSZbm"]},"priorities":{"$ref":"#/definitions/PrioritiesConfig","description":"Priority of messages\n\n* Info -> 5\n* Warn -> 7\n* Error -> 10"}},"required":["token","type","url"]},"PrioritiesConfig":{"type":"object","properties":{"info":{"type":"number","examples":[5]},"warn":{"type":"number","examples":[7]},"error":{"type":"number","examples":[10]}},"required":["info","warn","error"]},"NtfyConfig":{"type":"object","properties":{"type":{"type":"string","enum":["gotify","ntfy","apprise"],"description":"Webhook type. Valid values are:\n\n* gotify\n* ntfy","examples":["gotify"]},"name":{"type":"string","description":"A friendly name used to identify webhook config in logs"},"url":{"type":"string","description":"The URL of the Ntfy server","examples":["http://192.168.0.100:8078"]},"topic":{"type":"string","description":"The topic mutli-scrobbler should POST to"},"username":{"type":"string","description":"Required if topic is protected"},"password":{"type":"string","description":"Required if topic is protected"},"priorities":{"$ref":"#/definitions/PrioritiesConfig","description":"Priority of messages\n\n* Info -> 3\n* Warn -> 4\n* Error -> 5"}},"required":["topic","type","url"]},"AppriseConfig":{"type":"object","properties":{"type":{"type":"string","enum":["gotify","ntfy","apprise"],"description":"Webhook type. Valid values are:\n\n* gotify\n* ntfy","examples":["gotify"]},"name":{"type":"string","description":"A friendly name used to identify webhook config in logs"},"host":{"type":"string","description":"The URL of the apprise-api server","examples":["http://192.168.0.100:8078"]},"urls":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"If using [Stateless Endpoints](https://github.com/caronc/apprise-api?tab=readme-ov-file#stateless-solution) the Apprise config URL(s) to send"},"keys":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"If using [Persistent Store Endpoints](https://github.com/caronc/apprise-api?tab=readme-ov-file#persistent-storage-solution) the Configuration ID(s) to send to\n\nNote: If multiple keys are defined then MS will attempt to POST to each one individually"},"tags":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Optional [tag(s)](https://github.com/caronc/apprise-api?tab=readme-ov-file#tagging) to send in the notification payload"}},"required":["host","type"]},"LogOptions":{"type":"object","properties":{"level":{"$ref":"#/definitions/LogLevel","description":"Specify the minimum log level for all log outputs without their own level specified.\n\nDefaults to env `LOG_LEVEL` or `info` if not specified.","default":"info"},"file":{"anyOf":[{"$ref":"#/definitions/LogLevel"},{"type":"boolean","const":false},{"$ref":"#/definitions/FileLogOptions"}],"description":"Specify the minimum log level to output to rotating files or file output options. If `false` no log files will be created."},"console":{"$ref":"#/definitions/LogLevel","description":"Specify the minimum log level streamed to the console (or docker container)"}},"description":"Configure log levels and file options for an AppLogger.\n\n```ts\nconst infoLogger = loggerApp({\n level: 'info' // console and file will log any levels `info` and above\n});\n\nconst logger = loggerApp({\n console: 'debug', // console will log `debug` and higher\n file: 'warn' // file will log `warn` and higher\n});\n\nconst fileLogger = loggerRollingApp({\n console: 'debug', // console will log `debug` and higher\n file: {\n level: 'warn', // file will log `warn` and higher\n path: '/my/cool/path/output.log', // optionally, output to log file at this path\n frequency: 'hourly', // optionally, rotate hourly\n }\n});\n```"},"LogLevel":{"type":"string","enum":["silent","fatal","error","warn","info","log","verbose","debug"],"description":"Names of log levels that can be invoked on the logger\n\nFrom lowest to highest:\n\n* `debug`\n* `verbose`\n* `log`\n* `info`\n* `warn`\n* `error`\n* `fatal`\n* `silent` (will never output anything)\n\nWhen used in `LogOptions` specifies the **minimum** level the output should log at."},"FileLogOptions":{"type":"object","properties":{"timestamp":{"type":"string","enum":["unix","iso","auto"],"description":"For rolling log files\n\nWhen\n* value passed to rolling destination is a string (`path` from LogOptions is a string) and\n* `frequency` is defined\n\nThis determines the format of the datetime inserted into the log file name:\n\n* `unix` - unix epoch timestamp in milliseconds\n* `iso` - Full [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) datetime IE '2024-03-07T20:11:34Z'\n* `auto`\n * When frequency is `daily` only inserts date IE YYYY-MM-DD\n * Otherwise inserts full ISO8601 datetime","default":"auto"},"size":{"type":["number","string"],"description":"The maximum size of a given rolling log file.\n\nCan be combined with frequency. Use k, m and g to express values in KB, MB or GB.\n\nNumerical values will be considered as MB.","default":"10MB"},"frequency":{"anyOf":[{"type":"string","enum":["daily"]},{"type":"string","enum":["hourly"]},{"type":"number"}],"description":"The amount of time a given rolling log file is used. Can be combined with size.\n\nUse `daily` or `hourly` to rotate file every day (or every hour). Existing file within the current day (or hour) will be re-used.\n\nNumerical values will be considered as a number of milliseconds. Using a numerical value will always create a new file upon startup.","default":"daily"},"path":{"anyOf":[{"type":"string"},{"$comment":"() => string"}],"description":"The path and filename to use for log files.\n\nIf using rolling files the filename will be appended with `.N` (a number) BEFORE the extension based on rolling status.\n\nMay also be specified using env LOG_PATH or a function that returns a string.\n\nIf path is relative the absolute path will be derived from `logBaseDir` (in `LoggerAppExtras`) which defaults to CWD","default":"./logs/app.log"},"level":{"anyOf":[{"$ref":"#/definitions/LogLevel"},{"type":"boolean","const":false}],"description":"Specify the minimum log level to output to rotating files. If `false` no log files will be created."}}}}} \ No newline at end of file diff --git a/src/backend/common/schema/client.json b/src/backend/common/schema/client.json index c89a1f3..8686773 100644 --- a/src/backend/common/schema/client.json +++ b/src/backend/common/schema/client.json @@ -1,668 +1 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "anyOf": [ - { - "$ref": "#/definitions/LastfmClientConfig" - }, - { - "$ref": "#/definitions/ListenBrainzClientConfig" - }, - { - "$ref": "#/definitions/MalojaClientConfig" - } - ], - "definitions": { - "CommonClientData": { - "title": "CommonClientData", - "type": "object" - }, - "CommonClientOptions": { - "properties": { - "checkExistingScrobbles": { - "default": true, - "description": "Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.", - "examples": [ - true - ], - "title": "checkExistingScrobbles", - "type": "boolean" - }, - "deadLetterRetries": { - "default": 1, - "description": "Number of times MS should automatically retry scrobbles in dead letter queue", - "examples": [ - 1 - ], - "title": "deadLetterRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "refreshEnabled": { - "default": true, - "description": "Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history", - "examples": [ - true - ], - "title": "refreshEnabled", - "type": "boolean" - }, - "refreshInitialCount": { - "description": "The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call.", - "title": "refreshInitialCount", - "type": "number" - }, - "refreshMinInterval": { - "default": 5000, - "description": "Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.", - "examples": [ - 5000 - ], - "title": "refreshMinInterval", - "type": "number" - }, - "refreshStaleAfter": { - "default": 60, - "description": "Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.", - "examples": [ - 60 - ], - "title": "refreshStaleAfter", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "verbose": { - "description": "Options used for increasing verbosity of logging in MS (used for debugging)", - "properties": { - "match": { - "$ref": "#/definitions/MatchLoggingOptions", - "title": "match" - } - }, - "title": "verbose", - "type": "object" - } - }, - "title": "CommonClientOptions", - "type": "object" - }, - "ConditionalSearchAndReplaceTerm": { - "properties": { - "replace": { - "description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace", - "title": "replace", - "type": "string" - }, - "search": { - "anyOf": [ - { - "$ref": "#/definitions/RegExp" - }, - { - "type": "string" - } - ], - "description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression as a string, or an actual RegExp object", - "title": "search" - }, - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "required": [ - "replace", - "search" - ], - "title": "ConditionalSearchAndReplaceTerm", - "type": "object" - }, - "LastfmClientConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using LastFM as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "allOf": [ - { - "$ref": "#/definitions/CommonClientData" - }, - { - "$ref": "#/definitions/LastfmData" - } - ], - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - } - }, - "required": [ - "data", - "name" - ], - "title": "LastfmClientConfig", - "type": "object" - }, - "LastfmData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastfmData", - "type": "object" - }, - "ListenBrainzClientConfig": { - "properties": { - "configureAs": { - "default": "client", - "description": "Should always be `client` when using Listenbrainz as a client", - "enum": [ - "client", - "source" - ], - "examples": [ - "client" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - } - }, - "required": [ - "data", - "name" - ], - "title": "ListenBrainzClientConfig", - "type": "object" - }, - "ListenBrainzClientData": { - "properties": { - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzClientData", - "type": "object" - }, - "MalojaClientConfig": { - "properties": { - "data": { - "$ref": "#/definitions/MalojaClientData", - "description": "Specific data required to configure this client", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this client. Used with sources to restrict where scrobbles are sent.", - "examples": [ - "MyConfig" - ], - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonClientOptions", - "title": "options" - } - }, - "required": [ - "data", - "name" - ], - "title": "MalojaClientConfig", - "type": "object" - }, - "MalojaClientData": { - "properties": { - "apiKey": { - "description": "API Key for Maloja server", - "examples": [ - "myApiKey" - ], - "title": "apiKey", - "type": "string" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "url": { - "description": "URL for maloja server", - "examples": [ - "http://localhost:42010" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "apiKey", - "url" - ], - "title": "MalojaClientData", - "type": "object" - }, - "MatchLoggingOptions": { - "description": "Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging.", - "properties": { - "confidenceBreakdown": { - "default": false, - "description": "Include confidence breakdowns in track match logging, if applicable", - "examples": [ - false - ], - "title": "confidenceBreakdown", - "type": "boolean" - }, - "onMatch": { - "default": false, - "description": "Log to DEBUG when a new track DOES match an existing scrobble", - "examples": [ - false - ], - "title": "onMatch", - "type": "boolean" - }, - "onNoMatch": { - "default": false, - "description": "Log to DEBUG when a new track does NOT match an existing scrobble", - "examples": [ - false - ], - "title": "onNoMatch", - "type": "boolean" - } - }, - "title": "MatchLoggingOptions", - "type": "object" - }, - "PlayTransformConfig": { - "properties": { - "compare": { - "properties": { - "candidate": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "candidate" - }, - "existing": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "existing" - } - }, - "title": "compare", - "type": "object" - }, - "postCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "postCompare" - }, - "preCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "preCompare" - } - }, - "title": "PlayTransformConfig", - "type": "object" - }, - "PlayTransformOptions": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformConfig" - }, - { - "properties": { - "log": { - "enum": [ - "all", - false, - true - ], - "title": "log" - } - }, - "type": "object" - } - ], - "title": "PlayTransformOptions" - }, - "PlayTransformParts": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformPartsAtomic" - }, - { - "properties": { - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "type": "object" - } - ], - "title": "PlayTransformParts" - }, - "PlayTransformPartsAtomic": { - "properties": { - "album": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "album", - "type": "array" - }, - "artists": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "artists", - "type": "array" - }, - "title": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "title", - "type": "array" - } - }, - "title": "PlayTransformPartsAtomic", - "type": "object" - }, - "PlayTransformPartsConfig": { - "anyOf": [ - { - "items": { - "$ref": "#/definitions/PlayTransformParts" - }, - "type": "array" - }, - { - "$ref": "#/definitions/PlayTransformParts" - } - ], - "title": "PlayTransformPartsConfig" - }, - "RegExp": { - "properties": { - "dotAll": { - "title": "dotAll", - "type": "boolean" - }, - "flags": { - "title": "flags", - "type": "string" - }, - "global": { - "title": "global", - "type": "boolean" - }, - "hasIndices": { - "title": "hasIndices", - "type": "boolean" - }, - "ignoreCase": { - "title": "ignoreCase", - "type": "boolean" - }, - "lastIndex": { - "title": "lastIndex", - "type": "number" - }, - "multiline": { - "title": "multiline", - "type": "boolean" - }, - "source": { - "title": "source", - "type": "string" - }, - "sticky": { - "title": "sticky", - "type": "boolean" - }, - "unicode": { - "title": "unicode", - "type": "boolean" - } - }, - "required": [ - "dotAll", - "flags", - "global", - "hasIndices", - "ignoreCase", - "lastIndex", - "multiline", - "source", - "sticky", - "unicode" - ], - "title": "RegExp", - "type": "object" - }, - "SearchAndReplaceTerm": { - "anyOf": [ - { - "$ref": "#/definitions/ConditionalSearchAndReplaceTerm" - }, - { - "type": "string" - } - ], - "title": "SearchAndReplaceTerm" - }, - "WhenParts": { - "properties": { - "album": { - "title": "album", - "type": "string" - }, - "artists": { - "title": "artists", - "type": "string" - }, - "title": { - "title": "title", - "type": "string" - } - }, - "title": "WhenParts", - "type": "object" - } - } -} - +{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/ClientConfig","definitions":{"ClientConfig":{"anyOf":[{"$ref":"#/definitions/MalojaClientConfig"},{"$ref":"#/definitions/LastfmClientConfig"},{"$ref":"#/definitions/ListenBrainzClientConfig"}]},"MalojaClientConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/MalojaClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"}},"required":["data","name"]},"MalojaClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for maloja server","examples":["http://localhost:42010"]},"apiKey":{"type":"string","description":"API Key for Maloja server","examples":["myApiKey"]}},"required":["url","apiKey"]},"CommonClientOptions":{"type":"object","properties":{"refreshEnabled":{"type":"boolean","description":"Try to get fresh scrobble history from client when tracks to be scrobbled are newer than the last scrobble found in client history","default":true,"examples":[true]},"refreshStaleAfter":{"type":"number","description":"Refresh scrobbled plays from upstream service if last refresh was at least X seconds ago\n\n**In most case this setting does NOT need to be changed.** The default value is sufficient for the majority of use-cases. Increasing this setting may increase upstream service load and slow down scrobbles.\n\nThis setting should only be changed in specific scenarios where MS is handling multiple \"relaying\" client-services (IE lfm -> lz -> lfm) and there is the potential for a client to be out of sync after more than a few seconds.","examples":[60],"default":60},"refreshMinInterval":{"type":"number","description":"Minimum time (milliseconds) required to pass before upstream scrobbles can be refreshed.\n\n**In most case this setting does NOT need to be changed.** This will always be equal to or smaller than `refreshStaleAfter`.","default":5000,"examples":[5000]},"refreshInitialCount":{"type":"number","description":"The number of tracks to retrieve on initial refresh (related to scrobbleBacklogCount). If not specified this is the maximum supported by the client in 1 API call."},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"checkExistingScrobbles":{"type":"boolean","description":"Check client for an existing scrobble at the same recorded time as the \"new\" track to be scrobbled. If an existing scrobble is found this track is not track scrobbled.","default":true,"examples":[true]},"verbose":{"type":"object","properties":{"match":{"$ref":"#/definitions/MatchLoggingOptions"}},"description":"Options used for increasing verbosity of logging in MS (used for debugging)"},"deadLetterRetries":{"type":"number","description":"Number of times MS should automatically retry scrobbles in dead letter queue","default":1,"examples":[1]},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"MatchLoggingOptions":{"type":"object","properties":{"onNoMatch":{"type":"boolean","description":"Log to DEBUG when a new track does NOT match an existing scrobble","default":false,"examples":[false]},"onMatch":{"type":"boolean","description":"Log to DEBUG when a new track DOES match an existing scrobble","default":false,"examples":[false]},"confidenceBreakdown":{"type":"boolean","description":"Include confidence breakdowns in track match logging, if applicable","default":false,"examples":[false]}},"description":"Scrobble matching (between new source track and existing client scrobbles) logging options. Used for debugging."},"PlayTransformOptions":{"type":"object","properties":{"log":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["all"]}]},"preCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"compare":{"type":"object","properties":{"candidate":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"existing":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"postCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"PlayTransformPartsConfig":{"anyOf":[{"$ref":"#/definitions/PlayTransformPartsArray%3CSearchAndReplaceTerm%3E"},{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}]},"PlayTransformPartsArray":{"type":"array","items":{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}},"PlayTransformParts":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"title":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"artists":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"album":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}}}},"WhenConditionsConfig":{"$ref":"#/definitions/WhenConditions%3Cstring%3E"},"WhenConditions":{"type":"array","items":{"$ref":"#/definitions/WhenParts%3Cstring%3E"}},"WhenParts":{"$ref":"#/definitions/PlayTransformPartsAtomic%3Cstring%3E"},"PlayTransformPartsAtomic":{"type":"object","properties":{"title":{"type":"string"},"artists":{"type":"string"},"album":{"type":"string"}}},"SearchAndReplaceTerm":{"anyOf":[{"type":"string"},{"$ref":"#/definitions/ConditionalSearchAndReplaceTerm"}]},"ConditionalSearchAndReplaceTerm":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"search":{},"replace":{}},"required":["search","replace"]},"LastfmClientConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]}},"required":["apiKey","secret"],"description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using LastFM as a client","default":"client","examples":["client"]}},"required":["data","name"]},"ListenBrainzClientConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this client. Used with sources to restrict where scrobbles are sent.","examples":["MyConfig"]},"data":{"$ref":"#/definitions/ListenBrainzClientData","description":"Specific data required to configure this client"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"options":{"$ref":"#/definitions/CommonClientOptions"},"configureAs":{"type":"string","enum":["client","source"],"description":"Should always be `client` when using Listenbrainz as a client","default":"client","examples":["client"]}},"required":["data","name"]},"ListenBrainzClientData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]}}} \ No newline at end of file diff --git a/src/backend/common/schema/source.json b/src/backend/common/schema/source.json index 79e5d83..96b7c17 100644 --- a/src/backend/common/schema/source.json +++ b/src/backend/common/schema/source.json @@ -1,2659 +1 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "anyOf": [ - { - "$ref": "#/definitions/ChromecastSourceConfig" - }, - { - "$ref": "#/definitions/DeezerSourceConfig" - }, - { - "$ref": "#/definitions/JellySourceConfig" - }, - { - "$ref": "#/definitions/JellyApiSourceConfig" - }, - { - "$ref": "#/definitions/JRiverSourceConfig" - }, - { - "$ref": "#/definitions/KodiSourceConfig" - }, - { - "$ref": "#/definitions/LastfmSourceConfig" - }, - { - "$ref": "#/definitions/ListenBrainzSourceConfig" - }, - { - "$ref": "#/definitions/MopidySourceConfig" - }, - { - "$ref": "#/definitions/MPDSourceConfig" - }, - { - "$ref": "#/definitions/MPRISSourceConfig" - }, - { - "$ref": "#/definitions/MusikcubeSourceConfig" - }, - { - "$ref": "#/definitions/PlexSourceConfig" - }, - { - "$ref": "#/definitions/SpotifySourceConfig" - }, - { - "$ref": "#/definitions/SubSonicSourceConfig" - }, - { - "$ref": "#/definitions/TautulliSourceConfig" - }, - { - "$ref": "#/definitions/VLCSourceConfig" - }, - { - "$ref": "#/definitions/WebScrobblerSourceConfig" - }, - { - "$ref": "#/definitions/YTMusicSourceConfig" - } - ], - "definitions": { - "ChromecastData": { - "properties": { - "allowUnknownMedia": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "boolean" - } - ], - "default": false, - "description": "Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property", - "title": "allowUnknownMedia" - }, - "blacklistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any application that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "blacklistApps" - }, - "blacklistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "blacklistDevices" - }, - "devices": { - "description": "A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set", - "items": { - "$ref": "#/definitions/ChromecastDeviceInfo" - }, - "title": "devices", - "type": "array" - }, - "forceMediaRecognitionOn": { - "description": "Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive", - "items": { - "type": "string" - }, - "title": "forceMediaRecognitionOn", - "type": "array" - }, - "useAutoDiscovery": { - "description": "Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set", - "title": "useAutoDiscovery", - "type": "boolean" - }, - "useAvahi": { - "default": false, - "description": "Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.", - "title": "useAvahi", - "type": "boolean" - }, - "whitelistApps": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "pandora" - ] - ], - "title": "whitelistApps" - }, - "whitelistDevices": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery", - "examples": [ - [ - "home-mini", - "family-tv" - ] - ], - "title": "whitelistDevices" - } - }, - "title": "ChromecastData", - "type": "object" - }, - "ChromecastDeviceInfo": { - "properties": { - "address": { - "description": "The IP address of the device", - "examples": [ - "192.168.0.115" - ], - "title": "address", - "type": "string" - }, - "name": { - "description": "A friendly name to identify this device", - "examples": [ - "MySmartTV" - ], - "title": "name", - "type": "string" - } - }, - "required": [ - "address", - "name" - ], - "title": "ChromecastDeviceInfo", - "type": "object" - }, - "ChromecastSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/ChromecastData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "ChromecastSourceConfig", - "type": "object" - }, - "CommonSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "CommonSourceOptions", - "type": "object" - }, - "ConditionalSearchAndReplaceTerm": { - "properties": { - "replace": { - "description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace", - "title": "replace", - "type": "string" - }, - "search": { - "anyOf": [ - { - "$ref": "#/definitions/RegExp" - }, - { - "type": "string" - } - ], - "description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression as a string, or an actual RegExp object", - "title": "search" - }, - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "required": [ - "replace", - "search" - ], - "title": "ConditionalSearchAndReplaceTerm", - "type": "object" - }, - "DeezerData": { - "properties": { - "clientId": { - "description": "deezer client id", - "examples": [ - "a89cba1569901a0671d5a9875fed4be1" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "deezer client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 60, - "description": "optional, how long to wait before calling spotify for new tracks (in seconds)", - "examples": [ - 60 - ], - "title": "interval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/deezer/callback", - "description": "deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/deezer/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "DeezerData", - "type": "object" - }, - "DeezerSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/DeezerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "DeezerSourceConfig", - "type": "object" - }, - "JRiverData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "If you have enabled authentication, the password you set", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:52199/MCWS/v1/", - "description": "URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`", - "examples": [ - "http://localhost:52199/MCWS/v1/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "If you have enabled authentication, the username you set", - "title": "username", - "type": "string" - } - }, - "required": [ - "url" - ], - "title": "JRiverData", - "type": "object" - }, - "JRiverSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JRiverData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "JRiverSourceConfig", - "type": "object" - }, - "JellyApiData": { - "properties": { - "apiKey": { - "description": "API Key to authenticate with.\n\nRequired if `password` is not provided.", - "title": "apiKey", - "type": "string" - }, - "devicesAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesAllow" - }, - "devicesBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history", - "title": "devicesBlock" - }, - "password": { - "description": "Password of the username to authenticate for\n\nRequired if `apiKey` is not provided.", - "title": "password", - "type": "string" - }, - "url": { - "description": "HOST:PORT of the Jellyfin server to connect to", - "title": "url", - "type": "string" - }, - "user": { - "description": "The username of the user to authenticate for or track scrobbles for", - "title": "user", - "type": "string" - }, - "usersAllow": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "const": true, - "type": "boolean" - }, - { - "type": "string" - } - ], - "description": "Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users", - "title": "usersAllow" - }, - "usersBlock": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Do not scrobble for these users (case-insensitive)", - "title": "usersBlock" - } - }, - "required": [ - "url", - "user" - ], - "title": "JellyApiData", - "type": "object" - }, - "JellyApiOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "JellyApiOptions", - "type": "object" - }, - "JellyApiSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyApiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/JellyApiOptions", - "title": "options" - } - }, - "required": [ - "data", - "options" - ], - "title": "JellyApiSourceConfig", - "type": "object" - }, - "JellyData": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName1" - ] - ], - "title": "servers" - }, - "users": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "users" - } - }, - "title": "JellyData", - "type": "object" - }, - "JellySourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/JellyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "JellySourceConfig", - "type": "object" - }, - "KodiData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "The password set for Remote Control via Web Sever", - "title": "password", - "type": "string" - }, - "url": { - "default": "http://localhost:8080/jsonrpc", - "description": "URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`", - "examples": [ - "http://localhost:8080/jsonrpc" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "The username set for Remote Control via Web Sever", - "title": "username", - "type": "string" - } - }, - "required": [ - "password", - "url", - "username" - ], - "title": "KodiData", - "type": "object" - }, - "KodiSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/KodiData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "KodiSourceConfig", - "type": "object" - }, - "LastFmSourceData": { - "properties": { - "apiKey": { - "description": "API Key generated from Last.fm account", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "apiKey", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/lastfm/callback", - "description": "Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.", - "examples": [ - "http://localhost:9078/lastfm/callback" - ], - "title": "redirectUri", - "type": "string" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "secret": { - "description": "Secret generated from Last.fm account", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "secret", - "type": "string" - }, - "session": { - "description": "Optional session id returned from a completed auth flow", - "title": "session", - "type": "string" - } - }, - "required": [ - "apiKey", - "secret" - ], - "title": "LastFmSourceData", - "type": "object" - }, - "LastfmSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/LastFmSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "LastfmSourceConfig", - "type": "object" - }, - "ListenBrainzSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "configureAs": { - "default": "source", - "description": "When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.", - "enum": [ - "source" - ], - "examples": [ - "source" - ], - "title": "configureAs", - "type": "string" - }, - "data": { - "$ref": "#/definitions/ListenBrainzSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "ListenBrainzSourceConfig", - "type": "object" - }, - "ListenBrainzSourceData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "token": { - "description": "User token for the user to scrobble for", - "examples": [ - "6794186bf-1157-4de6-80e5-uvb411f3ea2b" - ], - "title": "token", - "type": "string" - }, - "url": { - "default": "https://api.listenbrainz.org/", - "description": "URL for the ListenBrainz server, if not using the default", - "examples": [ - "https://api.listenbrainz.org/" - ], - "title": "url", - "type": "string" - }, - "username": { - "description": "Username of the user to scrobble for", - "title": "username", - "type": "string" - } - }, - "required": [ - "token", - "username" - ], - "title": "ListenBrainzSourceData", - "type": "object" - }, - "MPDData": { - "properties": { - "password": { - "description": "Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords", - "title": "password", - "type": "string" - }, - "path": { - "description": "If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory", - "title": "path", - "type": "string" - }, - "url": { - "default": "localhost:6600", - "description": "URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections", - "examples": [ - "localhost:6600" - ], - "title": "url", - "type": "string" - } - }, - "title": "MPDData", - "type": "object" - }, - "MPDSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPDData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/MPDSourceOptions", - "title": "options" - } - }, - "required": [ - "data", - "options" - ], - "title": "MPDSourceConfig", - "type": "object" - }, - "MPDSourceOptions": { - "properties": { - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "MPDSourceOptions", - "type": "object" - }, - "MPRISData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "DO NOT scrobble from any players that START WITH these values, case-insensitive", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "blacklist" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored", - "examples": [ - [ - "spotify", - "vlc" - ] - ], - "title": "whitelist" - } - }, - "title": "MPRISData", - "type": "object" - }, - "MPRISSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MPRISData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "MPRISSourceConfig", - "type": "object" - }, - "MopidyData": { - "properties": { - "albumBlacklist": { - "default": [ - "Soundcloud" - ], - "description": "Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.", - "examples": [ - [ - "Soundcloud", - "Mixcloud" - ] - ], - "items": { - "type": "string" - }, - "title": "albumBlacklist", - "type": "array" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "uriBlacklist": { - "description": "Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used.", - "items": { - "type": "string" - }, - "title": "uriBlacklist", - "type": "array" - }, - "uriWhitelist": { - "description": "Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list.", - "items": { - "type": "string" - }, - "title": "uriWhitelist", - "type": "array" - }, - "url": { - "default": "ws://localhost:6680/mopidy/ws/", - "description": "URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`", - "examples": [ - "ws://localhost:6680/mopidy/ws/" - ], - "title": "url", - "type": "string" - } - }, - "title": "MopidyData", - "type": "object" - }, - "MopidySourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MopidyData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "MopidySourceConfig", - "type": "object" - }, - "MusikcubeData": { - "properties": { - "device_id": { - "title": "device_id", - "type": "string" - }, - "password": { - "description": "Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password", - "title": "password", - "type": "string" - }, - "url": { - "default": "ws://localhost:7905", - "description": "URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`", - "examples": [ - "ws://localhost:7905" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "MusikcubeData", - "type": "object" - }, - "MusikcubeSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/MusikcubeData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "MusikcubeSourceConfig", - "type": "object" - }, - "PlayTransformConfig": { - "properties": { - "compare": { - "properties": { - "candidate": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "candidate" - }, - "existing": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "existing" - } - }, - "title": "compare", - "type": "object" - }, - "postCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "postCompare" - }, - "preCompare": { - "$ref": "#/definitions/PlayTransformPartsConfig", - "title": "preCompare" - } - }, - "title": "PlayTransformConfig", - "type": "object" - }, - "PlayTransformOptions": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformConfig" - }, - { - "properties": { - "log": { - "enum": [ - "all", - false, - true - ], - "title": "log" - } - }, - "type": "object" - } - ], - "title": "PlayTransformOptions" - }, - "PlayTransformParts": { - "allOf": [ - { - "$ref": "#/definitions/PlayTransformPartsAtomic" - }, - { - "properties": { - "when": { - "items": { - "$ref": "#/definitions/WhenParts" - }, - "title": "when", - "type": "array" - } - }, - "type": "object" - } - ], - "title": "PlayTransformParts" - }, - "PlayTransformPartsAtomic": { - "properties": { - "album": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "album", - "type": "array" - }, - "artists": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "artists", - "type": "array" - }, - "title": { - "items": { - "$ref": "#/definitions/SearchAndReplaceTerm" - }, - "title": "title", - "type": "array" - } - }, - "title": "PlayTransformPartsAtomic", - "type": "object" - }, - "PlayTransformPartsConfig": { - "anyOf": [ - { - "items": { - "$ref": "#/definitions/PlayTransformParts" - }, - "type": "array" - }, - { - "$ref": "#/definitions/PlayTransformParts" - } - ], - "title": "PlayTransformPartsConfig" - }, - "PlexSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "PlexSourceConfig", - "type": "object" - }, - "PlexSourceData": { - "properties": { - "libraries": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled", - "examples": [ - [ - "Audio", - "Music" - ] - ], - "title": "libraries" - }, - "servers": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled", - "examples": [ - [ - "MyServerName" - ] - ], - "title": "servers" - }, - "user": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled", - "examples": [ - [ - "MyUser1", - "MyUser2" - ] - ], - "title": "user" - } - }, - "title": "PlexSourceData", - "type": "object" - }, - "RegExp": { - "properties": { - "dotAll": { - "title": "dotAll", - "type": "boolean" - }, - "flags": { - "title": "flags", - "type": "string" - }, - "global": { - "title": "global", - "type": "boolean" - }, - "hasIndices": { - "title": "hasIndices", - "type": "boolean" - }, - "ignoreCase": { - "title": "ignoreCase", - "type": "boolean" - }, - "lastIndex": { - "title": "lastIndex", - "type": "number" - }, - "multiline": { - "title": "multiline", - "type": "boolean" - }, - "source": { - "title": "source", - "type": "string" - }, - "sticky": { - "title": "sticky", - "type": "boolean" - }, - "unicode": { - "title": "unicode", - "type": "boolean" - } - }, - "required": [ - "dotAll", - "flags", - "global", - "hasIndices", - "ignoreCase", - "lastIndex", - "multiline", - "source", - "sticky", - "unicode" - ], - "title": "RegExp", - "type": "object" - }, - "ScrobbleThresholds": { - "properties": { - "duration": { - "default": 240, - "description": "The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.", - "examples": [ - 240 - ], - "title": "duration", - "type": "number" - }, - "percent": { - "default": 50, - "description": "The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.", - "examples": [ - 50 - ], - "title": "percent", - "type": "number" - } - }, - "title": "ScrobbleThresholds", - "type": "object" - }, - "SearchAndReplaceTerm": { - "anyOf": [ - { - "$ref": "#/definitions/ConditionalSearchAndReplaceTerm" - }, - { - "type": "string" - } - ], - "title": "SearchAndReplaceTerm" - }, - "SpotifySourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SpotifySourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "SpotifySourceConfig", - "type": "object" - }, - "SpotifySourceData": { - "properties": { - "clientId": { - "description": "spotify client id", - "examples": [ - "787c921a2a2ab42320831aba0c8f2fc2" - ], - "title": "clientId", - "type": "string" - }, - "clientSecret": { - "description": "spotify client secret", - "examples": [ - "ec42e09d5ae0ee0f0816ca151008412a" - ], - "title": "clientSecret", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "redirectUri": { - "default": "http://localhost:9078/callback", - "description": "spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"", - "examples": [ - "http://localhost:9078/callback" - ], - "title": "redirectUri", - "type": "string" - } - }, - "required": [ - "clientId", - "clientSecret" - ], - "title": "SpotifySourceData", - "type": "object" - }, - "SubSonicSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/SubsonicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "SubSonicSourceConfig", - "type": "object" - }, - "SubsonicData": { - "properties": { - "ignoreTlsErrors": { - "default": false, - "description": "If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.", - "title": "ignoreTlsErrors", - "type": "boolean" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "legacyAuthentication": { - "default": false, - "description": "Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp", - "title": "legacyAuthentication", - "type": "boolean" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the user to login to the server with", - "examples": [ - "MyPassword" - ], - "title": "password", - "type": "string" - }, - "url": { - "description": "URL of the subsonic media server to query", - "examples": [ - "http://airsonic.local" - ], - "title": "url", - "type": "string" - }, - "user": { - "description": "Username to login to the server with", - "title": "user", - "type": "string" - } - }, - "required": [ - "password", - "url", - "user" - ], - "title": "SubsonicData", - "type": "object" - }, - "TautulliSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/PlexSourceData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "TautulliSourceConfig", - "type": "object" - }, - "VLCData": { - "properties": { - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - }, - "password": { - "description": "Password for the server", - "title": "password", - "type": "string" - }, - "url": { - "default": "localhost:8080", - "description": "URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc", - "examples": [ - "localhost:8080" - ], - "title": "url", - "type": "string" - } - }, - "required": [ - "password" - ], - "title": "VLCData", - "type": "object" - }, - "VLCSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/VLCData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/VLCSourceOptions", - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "VLCSourceConfig", - "type": "object" - }, - "VLCSourceOptions": { - "properties": { - "dumpVlcMetadata": { - "default": false, - "description": "Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.", - "title": "dumpVlcMetadata", - "type": "boolean" - }, - "filenamePatterns": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track", - "title": "filenamePatterns" - }, - "logFilenamePatterns": { - "default": false, - "description": "Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns", - "title": "logFilenamePatterns", - "type": "boolean" - }, - "logFilterFailure": { - "default": "warn", - "description": "If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.", - "enum": [ - "debug", - false, - "warn" - ], - "examples": [ - "warn" - ], - "title": "logFilterFailure" - }, - "logPayload": { - "default": false, - "description": "If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output", - "examples": [ - false - ], - "title": "logPayload", - "type": "boolean" - }, - "logPlayerState": { - "default": false, - "description": "For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output", - "examples": [ - false - ], - "title": "logPlayerState", - "type": "boolean" - }, - "maxPollRetries": { - "default": 5, - "description": "default # of automatic polling restarts on error", - "examples": [ - 5 - ], - "title": "maxPollRetries", - "type": "number" - }, - "maxRequestRetries": { - "default": 1, - "description": "default # of http request retries a source/client can make before error is thrown", - "examples": [ - 1 - ], - "title": "maxRequestRetries", - "type": "number" - }, - "playTransform": { - "$ref": "#/definitions/PlayTransformOptions", - "title": "playTransform" - }, - "retryMultiplier": { - "default": 1.5, - "description": "default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)", - "examples": [ - 1.5 - ], - "title": "retryMultiplier", - "type": "number" - }, - "scrobbleBacklog": { - "default": true, - "description": "If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history", - "examples": [ - true, - false - ], - "title": "scrobbleBacklog", - "type": "boolean" - }, - "scrobbleBacklogCount": { - "description": "The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports", - "title": "scrobbleBacklogCount", - "type": "number" - }, - "scrobbleThresholds": { - "$ref": "#/definitions/ScrobbleThresholds", - "description": "Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled.", - "title": "scrobbleThresholds" - } - }, - "title": "VLCSourceOptions", - "type": "object" - }, - "WebScrobblerData": { - "properties": { - "blacklist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Block scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "youtube" - ] - ], - "title": "blacklist" - }, - "slug": { - "description": "The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used", - "title": "slug", - "type": "string" - }, - "whitelist": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "string" - } - ], - "description": "Only allow scrobbling from specific WebScrobbler Connectors", - "examples": [ - [ - "mixcloud", - "soundcloud", - "bandcamp" - ] - ], - "title": "whitelist" - } - }, - "title": "WebScrobblerData", - "type": "object" - }, - "WebScrobblerSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/WebScrobblerData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "$ref": "#/definitions/CommonSourceOptions", - "title": "options" - } - }, - "title": "WebScrobblerSourceConfig", - "type": "object" - }, - "WhenParts": { - "properties": { - "album": { - "title": "album", - "type": "string" - }, - "artists": { - "title": "artists", - "type": "string" - }, - "title": { - "title": "title", - "type": "string" - } - }, - "title": "WhenParts", - "type": "object" - }, - "YTMusicData": { - "properties": { - "authUser": { - "description": "If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included", - "title": "authUser", - "type": [ - "string", - "number" - ] - }, - "cookie": { - "description": "The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.", - "examples": [ - "VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..." - ], - "title": "cookie", - "type": "string" - }, - "interval": { - "default": 10, - "description": "How long to wait before polling the source API for new tracks (in seconds)", - "examples": [ - 10 - ], - "title": "interval", - "type": "number" - }, - "maxInterval": { - "default": 30, - "description": "When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)", - "examples": [ - 30 - ], - "title": "maxInterval", - "type": "number" - } - }, - "required": [ - "cookie" - ], - "title": "YTMusicData", - "type": "object" - }, - "YTMusicSourceConfig": { - "properties": { - "clients": { - "description": "Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.", - "examples": [ - [ - "MyMalojaConfigName", - "MyLastFMConfigName" - ] - ], - "items": { - "type": "string" - }, - "title": "clients", - "type": "array" - }, - "data": { - "$ref": "#/definitions/YTMusicData", - "title": "data" - }, - "enable": { - "default": true, - "description": "Should MS use this client/source? Defaults to true", - "examples": [ - true - ], - "title": "enable", - "type": "boolean" - }, - "name": { - "description": "Unique identifier for this source.", - "title": "name", - "type": "string" - }, - "options": { - "allOf": [ - { - "$ref": "#/definitions/CommonSourceOptions" - }, - { - "properties": { - "logAuthUpdateChanges": { - "description": "When true MS will log to DEBUG what parts of the cookie are updated by YTM", - "title": "logAuthUpdateChanges", - "type": "boolean" - } - }, - "type": "object" - } - ], - "title": "options" - } - }, - "required": [ - "data" - ], - "title": "YTMusicSourceConfig", - "type": "object" - } - } -} - +{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/SourceConfig","definitions":{"SourceConfig":{"anyOf":[{"$ref":"#/definitions/SpotifySourceConfig"},{"$ref":"#/definitions/PlexSourceConfig"},{"$ref":"#/definitions/TautulliSourceConfig"},{"$ref":"#/definitions/DeezerSourceConfig"},{"$ref":"#/definitions/SubSonicSourceConfig"},{"$ref":"#/definitions/JellySourceConfig"},{"$ref":"#/definitions/JellyApiSourceConfig"},{"$ref":"#/definitions/LastfmSourceConfig"},{"$ref":"#/definitions/YTMusicSourceConfig"},{"$ref":"#/definitions/MPRISSourceConfig"},{"$ref":"#/definitions/MopidySourceConfig"},{"$ref":"#/definitions/ListenBrainzSourceConfig"},{"$ref":"#/definitions/JRiverSourceConfig"},{"$ref":"#/definitions/KodiSourceConfig"},{"$ref":"#/definitions/WebScrobblerSourceConfig"},{"$ref":"#/definitions/ChromecastSourceConfig"},{"$ref":"#/definitions/MusikcubeSourceConfig"},{"$ref":"#/definitions/MPDSourceConfig"},{"$ref":"#/definitions/VLCSourceConfig"}]},"SpotifySourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SpotifySourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"SpotifySourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)\n\nIt is unlikely you should need to change this unless you scrobble many very short tracks often\n\nReading:\n* https://developer.spotify.com/documentation/web-api/guides/rate-limits/\n* https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e\n * Rate limit may ~180 req/min\n* https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930\n * Informally indicated as 20 req/sec? Probably for burstiness","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"clientId":{"type":"string","description":"spotify client id","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"clientSecret":{"type":"string","description":"spotify client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"spotify redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/callback","examples":["http://localhost:9078/callback"]}},"required":["clientId","clientSecret"]},"CommonSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"ScrobbleThresholds":{"type":"object","properties":{"duration":{"type":["number","null"],"description":"The number of seconds a track has been listened to before it should be considered scrobbled.\n\nSet to null to disable.","default":240,"examples":[240]},"percent":{"type":["number","null"],"description":"The percentage (as an integer) of a track that should have been seen played before it should be scrobbled. Only used if the Source provides information about how long the track is.\n\nSet to null to disable.\n\nNOTE: This should be used with care when the Source is a \"polling\" type (has an 'interval' property). If the track is short and the interval is too high MS may ignore the track if percentage is high because it had not \"seen\" the track for long enough from first discovery, even if you have been playing the track for longer.","default":50,"examples":[50]}}},"PlayTransformOptions":{"type":"object","properties":{"log":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["all"]}]},"preCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"compare":{"type":"object","properties":{"candidate":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"},"existing":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"postCompare":{"$ref":"#/definitions/PlayTransformPartsConfig%3CSearchAndReplaceTerm%3E"}}},"PlayTransformPartsConfig":{"anyOf":[{"$ref":"#/definitions/PlayTransformPartsArray%3CSearchAndReplaceTerm%3E"},{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}]},"PlayTransformPartsArray":{"type":"array","items":{"$ref":"#/definitions/PlayTransformParts%3CSearchAndReplaceTerm%3E"}},"PlayTransformParts":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"title":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"artists":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}},"album":{"type":"array","items":{"$ref":"#/definitions/SearchAndReplaceTerm"}}}},"WhenConditionsConfig":{"$ref":"#/definitions/WhenConditions%3Cstring%3E"},"WhenConditions":{"type":"array","items":{"$ref":"#/definitions/WhenParts%3Cstring%3E"}},"WhenParts":{"$ref":"#/definitions/PlayTransformPartsAtomic%3Cstring%3E"},"PlayTransformPartsAtomic":{"type":"object","properties":{"title":{"type":"string"},"artists":{"type":"string"},"album":{"type":"string"}}},"SearchAndReplaceTerm":{"anyOf":[{"type":"string"},{"$ref":"#/definitions/ConditionalSearchAndReplaceTerm"}]},"ConditionalSearchAndReplaceTerm":{"type":"object","properties":{"when":{"$ref":"#/definitions/WhenConditionsConfig"},"search":{},"replace":{}},"required":["search","replace"]},"PlexSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"PlexSourceData":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"libraries":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of libraries to scrobble tracks from\n\nIf none are provided tracks from all libraries will be scrobbled","examples":[["Audio","Music"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName"]]}}},"TautulliSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/PlexSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"DeezerSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/DeezerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"DeezerData":{"type":"object","properties":{"clientId":{"type":"string","description":"deezer client id","examples":["a89cba1569901a0671d5a9875fed4be1"]},"clientSecret":{"type":"string","description":"deezer client secret","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"redirectUri":{"type":"string","description":"deezer redirect URI -- required only if not the default shown here. URI must end in \"callback\"","default":"http://localhost:9078/deezer/callback","examples":["http://localhost:9078/deezer/callback"]},"interval":{"type":"number","description":"optional, how long to wait before calling spotify for new tracks (in seconds)","default":60,"examples":[60]}},"required":["clientId","clientSecret"]},"SubSonicSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/SubsonicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"SubsonicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the subsonic media server to query","examples":["http://airsonic.local"]},"user":{"type":"string","description":"Username to login to the server with","examples":[["MyUser"]]},"password":{"type":"string","description":"Password for the user to login to the server with","examples":["MyPassword"]},"ignoreTlsErrors":{"type":"boolean","description":"If your subsonic server is using self-signed certs you may need to disable TLS errors in order to get a connection\n\nWARNING: This should be used with caution as your traffic may not be encrypted.","default":false},"legacyAuthentication":{"type":"boolean","description":"Older Subsonic versions, and some badly implemented servers (Nextcloud), use legacy authentication which sends your password in CLEAR TEXT. This is less secure than the newer, recommended hashing authentication method but in some cases it is needed. See \"Authentication\" section here => https://www.subsonic.org/pages/api.jsp\n\nIf this option is not specified it will be turned on if the subsonic server responds with error code 41 \"Token authentication not supported for LDAP users.\" -- See Error Handling section => https://www.subsonic.org/pages/api.jsp","default":false}},"required":["url","user","password"]},"JellySourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"JellyData":{"type":"object","properties":{"users":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of users to scrobble tracks from\n\nIf none are provided tracks from all users will be scrobbled","examples":[["MyUser1","MyUser2"]]},"servers":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"optional list of servers to scrobble tracks from\n\nIf none are provided tracks from all servers will be scrobbled","examples":[["MyServerName1"]]}}},"JellyApiSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JellyApiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/JellyApiOptions"}},"required":["data","options"]},"JellyApiData":{"type":"object","properties":{"url":{"type":"string","description":"HOST:PORT of the Jellyfin server to connect to"},"user":{"type":"string","description":"The username of the user to authenticate for or track scrobbles for"},"password":{"type":"string","description":"Password of the username to authenticate for\n\nRequired if `apiKey` is not provided."},"apiKey":{"type":"string","description":"API Key to authenticate with.\n\nRequired if `password` is not provided."},"usersAllow":{"anyOf":[{"type":"string"},{"type":"boolean","enum":[true]},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble for specific users (case-insensitive)\n\nIf `true` MS will scrobble activity from all users"},"usersBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble for these users (case-insensitive)"},"devicesAllow":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"},"devicesBlock":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Do not scrobble if device or application name contains strings from this list (case-insensitive)\n\nNote: This only applies to real-time scrobbling as JF does not track device info in user activity history"}},"required":["url","user"]},"JellyApiOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"LastfmSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/LastFmSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `lastfm.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]}},"required":["data"]},"LastFmSourceData":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"apiKey":{"type":"string","description":"API Key generated from Last.fm account","examples":["787c921a2a2ab42320831aba0c8f2fc2"]},"secret":{"type":"string","description":"Secret generated from Last.fm account","examples":["ec42e09d5ae0ee0f0816ca151008412a"]},"session":{"type":"string","description":"Optional session id returned from a completed auth flow"},"redirectUri":{"type":"string","description":"Optional URI to use for callback. Specify this if callback should be different than the default. MUST have \"lastfm/callback\" in the URL somewhere.","default":"http://localhost:9078/lastfm/callback","examples":["http://localhost:9078/lastfm/callback"]},"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]}},"required":["apiKey","secret"]},"YTMusicSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/YTMusicData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"type":"object","properties":{"logAuthUpdateChanges":{"type":"boolean","description":"When true MS will log to DEBUG what parts of the cookie are updated by YTM"},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}}},"required":["data"]},"YTMusicData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"cookie":{"type":"string","description":"The cookie retrieved from the Request Headers of music.youtube.com after logging in.\n\nSee https://github.com/nickp10/youtube-music-ts-api/blob/master/DOCUMENTATION.md#authenticate and https://ytmusicapi.readthedocs.io/en/latest/setup.html#copy-authentication-headers for how to retrieve this value.","examples":["VISITOR_INFO1_LIVE=jMp2xA1Xz2_PbVc; __Secure-3PAPISID=3AxsXpy0M/AkISpjek; ..."]},"authUser":{"type":["number","string"],"description":"If the 'X-Goog-AuthUser' header is present in the Request Headers for music.youtube.com it must also be included","examples":[[0]]}},"required":["cookie"]},"MPRISSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPRISData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"MPRISData":{"type":"object","properties":{"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any players that START WITH these values, case-insensitive","examples":[["spotify","vlc"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY from any players that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","vlc"]]}}},"MopidySourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MopidyData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"MopidyData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Mopidy HTTP server to connect to\n\nYou MUST have Mopidy-HTTP extension enabled: https://mopidy.com/ext/http\n\nmulti-scrobbler connects to the WebSocket endpoint that ultimately looks like this => `ws://localhost:6680/mopidy/ws/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `6680`\n* Path => `/mopidy/ws/`","examples":["ws://localhost:6680/mopidy/ws/"],"default":"ws://localhost:6680/mopidy/ws/"},"uriBlacklist":{"type":"array","items":{"type":"string"},"description":"Do not scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Don't scrobble tracks from soundcloud by adding 'soundcloud' to this list.\n\nList is ignored if uriWhitelist is used."},"uriWhitelist":{"type":"array","items":{"type":"string"},"description":"Only scrobble tracks whose URI STARTS WITH any of these strings, case-insensitive\n\nEX: Only scrobble tracks from soundcloud by adding 'soundcloud' to this list."},"albumBlacklist":{"type":"array","items":{"type":"string"},"description":"Remove album data that matches any case-insensitive string from this list when scrobbling,\n\nFor certain sources (Soundcloud) Mopidy does not have all track info (Album) and will instead use \"Soundcloud\" as the Album name. You can prevent multi-scrobbler from using this bad Album data by adding the fake name to this list. Multi-scrobbler will still scrobble the track, just without the bad data.","examples":[["Soundcloud","Mixcloud"]],"default":["Soundcloud"]}}},"ListenBrainzSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ListenBrainzSourceData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"},"configureAs":{"type":"string","enum":["source"],"description":"When used in `listenbrainz.config` this tells multi-scrobbler whether to use this data to configure a source or client.","default":"source","examples":["source"]}},"required":["data"]},"ListenBrainzSourceData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"url":{"type":"string","description":"URL for the ListenBrainz server, if not using the default","examples":["https://api.listenbrainz.org/"],"default":"https://api.listenbrainz.org/"},"token":{"type":"string","description":"User token for the user to scrobble for","examples":["6794186bf-1157-4de6-80e5-uvb411f3ea2b"]},"username":{"type":"string","description":"Username of the user to scrobble for"}},"required":["token","username"]},"JRiverSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/JRiverData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"JRiverData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the JRiver HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:52199/MCWS/v1/`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `52199`\n* Path => `/MCWS/v1/`","examples":["http://localhost:52199/MCWS/v1/"],"default":"http://localhost:52199/MCWS/v1/"},"username":{"type":"string","description":"If you have enabled authentication, the username you set"},"password":{"type":"string","description":"If you have enabled authentication, the password you set"}},"required":["url"]},"KodiSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/KodiData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"KodiData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL of the Kodi HTTP server to connect to\n\nmulti-scrobbler connects to the Web Service Interface endpoint that ultimately looks like this => `http://yourDomain:8080/jsonrpc`\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `http://`\n* Hostname => `localhost`\n* Port => `8080`\n* Path => `/jsonrpc`","examples":["http://localhost:8080/jsonrpc"],"default":"http://localhost:8080/jsonrpc"},"username":{"type":"string","description":"The username set for Remote Control via Web Sever"},"password":{"type":"string","description":"The password set for Remote Control via Web Sever"}},"required":["url","username","password"]},"WebScrobblerSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/WebScrobblerData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}}},"WebScrobblerData":{"type":"object","properties":{"slug":{"type":["string","null"],"description":"The URL ending that should be used to identify scrobbles for this source\n\nIn WebScrobbler's Webhook you must set an 'API URL'. All MS WebScrobbler sources must start like:\n\nhttp://localhost:9078/api/webscrobbler\n\nIf you are using multiple WebScrobbler sources (scrobbles for many users) you must use a slug to match Sources with each users extension.\n\nExample:\n\n* slug: 'usera' => API URL: http://localhost:9078/api/webscrobbler/usera\n* slug: 'userb' => API URL: http://localhost:9078/api/webscrobbler/userb\n\nIf no slug is found from an extension's incoming webhook event the first WebScrobbler source without a slug will be used"},"blacklist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Block scrobbling from specific WebScrobbler Connectors","examples":[["youtube"]]},"whitelist":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Only allow scrobbling from specific WebScrobbler Connectors","examples":[["mixcloud","soundcloud","bandcamp"]]}}},"ChromecastSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/ChromecastData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"ChromecastData":{"type":"object","properties":{"blacklistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any cast devices that START WITH these values, case-insensitive\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"whitelistDevices":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any cast device that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored\n\nUseful when used with auto discovery","examples":[["home-mini","family-tv"]]},"blacklistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"DO NOT scrobble from any application that START WITH these values, case-insensitive","examples":[["spotify","pandora"]]},"whitelistApps":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"ONLY scrobble from any application that START WITH these values, case-insensitive\n\nIf whitelist is present then blacklist is ignored","examples":[["spotify","pandora"]]},"useAvahi":{"type":"boolean","description":"Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying\n\nUseful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.","default":false},"useAutoDiscovery":{"type":"boolean","description":"Use mDNS to discovery Google Cast devices on your next automatically?\n\nIf not explicitly set then it is TRUE if `devices` is not set"},"devices":{"type":"array","items":{"$ref":"#/definitions/ChromecastDeviceInfo"},"description":"A list of Google Cast devices to monitor\n\nIf this is used then `useAutoDiscovery` is set to FALSE, if not explicitly set"},"allowUnknownMedia":{"anyOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"Chromecast Apps report a \"media type\" in the status info returned for whatever is currently playing\n\n* If set to TRUE then Music AND Generic/Unknown media will be tracked for ALL APPS\n* If set to FALSE then only media explicitly typed as Music will be tracked for ALL APPS\n* If set to a list then only Apps whose name contain one of these values, case-insensitive, will have Music AND Generic/Unknown tracked\n\nSee https://developers.google.com/cast/docs/media/messages#MediaInformation \"metadata\" property","default":false},"forceMediaRecognitionOn":{"type":"array","items":{"type":"string"},"description":"Media provided by any App whose name is listed here will ALWAYS be tracked, regardless of the \"media type\" reported\n\nApps will be recognized if they CONTAIN any of these values, case-insensitive"}}},"ChromecastDeviceInfo":{"type":"object","properties":{"name":{"type":"string","description":"A friendly name to identify this device","examples":["MySmartTV"]},"address":{"type":"string","description":"The IP address of the device","examples":["192.168.0.115"]}},"required":["name","address"]},"MusikcubeSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MusikcubeData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/CommonSourceOptions"}},"required":["data"]},"MusikcubeData":{"type":"object","properties":{"url":{"type":"string","description":"URL of the Musikcube Websocket (Metadata) server to connect to\n\nYou MUST have enabled 'metadata' server and set a password: https://github.com/clangen/musikcube/wiki/remote-api-documentation\n * musikcube -> settings -> server setup\n\nThe URL you provide here will have all parts not explicitly defined filled in for you so if these are not the default you must define them.\n\nParts => [default value]\n\n* Protocol => `ws://`\n* Hostname => `localhost`\n* Port => `7905`","examples":["ws://localhost:7905"],"default":"ws://localhost:7905"},"password":{"type":"string","description":"Password set in Musikcube https://github.com/clangen/musikcube/wiki/remote-api-documentation\n\n* musikcube -> settings -> server setup -> password"},"device_id":{"type":"string"}},"required":["password"]},"MPDSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/MPDData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/MPDSourceOptions"}},"required":["data","options"]},"MPDData":{"type":"object","properties":{"url":{"type":"string","description":"URL:PORT of the MPD server to connect to\n\nTo use this you must have TCP connections enabled for your MPD server https://mpd.readthedocs.io/en/stable/user.html#client-connections","examples":["localhost:6600"],"default":"localhost:6600"},"path":{"type":"string","description":"If using socket specify the path instead of url.\n\ntrailing `~` is replaced by your home directory"},"password":{"type":"string","description":"Password for the server, if set https://mpd.readthedocs.io/en/stable/user.html#permissions-and-passwords"}}},"MPDSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"}}},"VLCSourceConfig":{"type":"object","properties":{"name":{"type":"string","description":"Unique identifier for this source."},"data":{"$ref":"#/definitions/VLCData"},"enable":{"type":"boolean","description":"Should MS use this client/source? Defaults to true","default":true,"examples":[true]},"clients":{"type":"array","items":{"type":"string"},"description":"Restrict scrobbling tracks played from this source to Clients with names from this list. If list is empty is not present Source scrobbles to all configured Clients.","examples":[["MyMalojaConfigName","MyLastFMConfigName"]]},"options":{"$ref":"#/definitions/VLCSourceOptions"}},"required":["data"]},"VLCData":{"type":"object","properties":{"interval":{"type":"number","description":"How long to wait before polling the source API for new tracks (in seconds)","default":10,"examples":[10]},"maxInterval":{"type":"number","description":"When there has been no new activity from the Source API multi-scrobbler will gradually increase the wait time between polling up to this value (in seconds)","default":30,"examples":[30]},"url":{"type":"string","description":"URL:PORT of the VLC server to connect to\n\nTo use this you must have the Web (http) interface module enabled and a password set https://foxxmd.github.io/multi-scrobbler/docs/configuration#vlc","examples":["localhost:8080"],"default":"localhost:8080"},"password":{"type":"string","description":"Password for the server"}},"required":["password"]},"VLCSourceOptions":{"type":"object","properties":{"maxRequestRetries":{"type":"number","description":"default # of http request retries a source/client can make before error is thrown","default":1,"examples":[1]},"retryMultiplier":{"type":"number","description":"default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying)","default":1.5,"examples":[1.5]},"maxPollRetries":{"type":"number","description":"default # of automatic polling restarts on error","default":5,"examples":[5]},"logPayload":{"type":"boolean","description":"If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload)\nthen setting this option to true will make MS log the payload JSON to DEBUG output","default":false,"examples":[false]},"logFilterFailure":{"type":["boolean","string"],"enum":[false,"debug","warn"],"description":"If this source has INGRESS to MS and has filters this determines how MS logs when a payload (event) fails a defined filter (IE users/servers/library filters)\n\n* `false` => do not log\n* `debug` => log to DEBUG level\n* `warn` => log to WARN level (default)\n\nHint: This is useful if you are sure this source is setup correctly and you have multiple other sources. Set to `debug` or `false` to reduce log noise.","default":"warn","examples":["warn"]},"logPlayerState":{"type":"boolean","description":"For Sources that track Player State (currently playing) this logs a simple player state/summary to DEBUG output","default":false,"examples":[false]},"scrobbleBacklog":{"type":"boolean","description":"If this source\n\n* supports fetching a listen history\n* and this option is enabled\n\nthen on startup MS will attempt to scrobble the recent listens from that history","default":true,"examples":[true,false]},"scrobbleThresholds":{"$ref":"#/definitions/ScrobbleThresholds","description":"Set thresholds for when multi-scrobbler should consider a tracked play to be \"scrobbable\". If both duration and percent are defined then if either condition is met the track is scrobbled."},"scrobbleBacklogCount":{"type":"number","description":"The number of listens to fetch when scrobbling from backlog\n\n* Only applies if this source supports fetching a listen history\n* If not specified it defaults to the maximum number of listens the source API supports"},"playTransform":{"$ref":"#/definitions/PlayTransformOptions"},"filenamePatterns":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"A list of regular expressions to use to extract metadata (title, album, artist) from a filename\n\nUsed when VLC reports only the filename for the current audio track"},"logFilenamePatterns":{"type":"boolean","description":"Log to DEBUG when a filename-only track is matched or not matched by filenamePatterns","default":false},"dumpVlcMetadata":{"type":"boolean","description":"Dump all the metadata VLC reports for an audio track to DEBUG.\n\nUse this if reporting an issue with VLC not correctly capturing metadata for a track.","default":false}}}}} \ No newline at end of file diff --git a/src/backend/index.ts b/src/backend/index.ts index fe72ce9..94e033b 100644 --- a/src/backend/index.ts +++ b/src/backend/index.ts @@ -16,7 +16,7 @@ import { initServer } from "./server/index.js"; import { createHeartbeatClientsTask } from "./tasks/heartbeatClients.js"; import { createHeartbeatSourcesTask } from "./tasks/heartbeatSources.js"; import { parseBool, readJson, sleep } from "./utils.js"; -import { getTsConfigGenerator } from './utils/SchemaUtils.js'; +import { createVegaGenerator } from './utils/SchemaUtils.js'; dayjs.extend(utc) dayjs.extend(isBetween); @@ -86,7 +86,7 @@ const configDir = process.env.CONFIG_DIR || path.resolve(projectDir, `./config`) initLogger.info(`Version: ${root.get('version')}`); initLogger.info('Generating schema definitions...'); - getTsConfigGenerator(); + createVegaGenerator() initLogger.info('Schema definitions generated'); initServer(logger, appLoggerStream, output); diff --git a/src/backend/scrobblers/ScrobbleClients.ts b/src/backend/scrobblers/ScrobbleClients.ts index e649992..a40c95e 100644 --- a/src/backend/scrobblers/ScrobbleClients.ts +++ b/src/backend/scrobblers/ScrobbleClients.ts @@ -17,7 +17,7 @@ import AbstractScrobbleClient from "./AbstractScrobbleClient.js"; import LastfmScrobbler from "./LastfmScrobbler.js"; import ListenbrainzScrobbler from "./ListenbrainzScrobbler.js"; import MalojaScrobbler from "./MalojaScrobbler.js"; -import { Definition } from 'typescript-json-schema'; +import { Definition } from 'ts-json-schema-generator'; type groupedNamedConfigs = {[key: string]: ParsedConfig[]}; diff --git a/src/backend/sources/ScrobbleSources.ts b/src/backend/sources/ScrobbleSources.ts index 2088dae..3f2061e 100644 --- a/src/backend/sources/ScrobbleSources.ts +++ b/src/backend/sources/ScrobbleSources.ts @@ -50,7 +50,7 @@ import TautulliSource from "./TautulliSource.js"; import { VLCSource } from "./VLCSource.js"; import { WebScrobblerSource } from "./WebScrobblerSource.js"; import YTMusicSource from "./YTMusicSource.js"; -import { Definition } from 'typescript-json-schema'; +import { Definition } from 'ts-json-schema-generator'; import { getTypeSchemaFromConfigGenerator } from '../utils/SchemaUtils.js'; type groupedNamedConfigs = {[key: string]: ParsedConfig[]}; diff --git a/src/backend/utils/SchemaStaticUtil.ts b/src/backend/utils/SchemaStaticUtil.ts new file mode 100644 index 0000000..8f4bb55 --- /dev/null +++ b/src/backend/utils/SchemaStaticUtil.ts @@ -0,0 +1,19 @@ +import { writeFileSync } from "node:fs"; +import { resolve } from "path"; +import { projectDir } from "../common/index.js"; +import {getTypeSchemaFromConfigGenerator} from "./SchemaUtils.js"; + +const client = getTypeSchemaFromConfigGenerator('ClientConfig'); +writeFileSync(resolve(projectDir, 'src/backend/common/schema/client.json'), JSON.stringify(client)); + +const source = getTypeSchemaFromConfigGenerator('SourceConfig'); +writeFileSync(resolve(projectDir, 'src/backend/common/schema/source.json'), JSON.stringify(source)); + +const aio = getTypeSchemaFromConfigGenerator('AIOConfig'); +writeFileSync(resolve(projectDir, 'src/backend/common/schema/aio.json'), JSON.stringify(aio)); + +const aio_client = getTypeSchemaFromConfigGenerator('AIOClientConfig'); +writeFileSync(resolve(projectDir, 'src/backend/common/schema/aio-client.json'), JSON.stringify(aio_client)); + +const aio_source = getTypeSchemaFromConfigGenerator('AIOSourceConfig'); +writeFileSync(resolve(projectDir, 'src/backend/common/schema/aio-source.json'), JSON.stringify(aio_source)); diff --git a/src/backend/utils/SchemaUtils.ts b/src/backend/utils/SchemaUtils.ts index 2c02624..35c4654 100644 --- a/src/backend/utils/SchemaUtils.ts +++ b/src/backend/utils/SchemaUtils.ts @@ -1,50 +1,56 @@ -import * as TJS from "typescript-json-schema"; -import {sync} from "glob"; import { resolve } from "path"; import { projectDir } from "../common/index.js"; +import { + Definition as TSJDefinition, + createFormatter, + CompletedConfig as TSJCompletedConfig, + DEFAULT_CONFIG, + createProgram, + createParser, + SchemaGenerator, LiteralType, LiteralTypeFormatter +} from "ts-json-schema-generator"; -// const includeOnly = [ -// sync(resolve(projectDir, "src/backend/**/*.ts"), {ignore: resolve(projectDir, "src/backend/tests/**/*")}), -// sync(resolve(projectDir, "src/core/**/*.ts")) -// ].flat(1); +// https://github.com/vega/ts-json-schema-generator/issues/1899#issuecomment-2407674526 +// https://github.com/vega/ts-json-schema-generator?tab=readme-ov-file#custom-formatting +class CustomLiteralTypeFormatter extends LiteralTypeFormatter { + public getDefinition(type: LiteralType): TSJDefinition { + const result = super.getDefinition(type); -export const buildSchemaGenerator = (program?: TJS.Program, settings: TJS.PartialArgs = {}) => { - return TJS.buildGenerator(program, {...defaultGeneratorArgs, ...settings}); -} - -let configProgram: TJS.Program, -generatorFromConfig: TJS.JsonSchemaGenerator; + if ("const" in result && result.const) { + return { type: result.type, enum: [result.const] }; + } -export const getTsConfigProgram = (): TJS.Program => { - if(configProgram === undefined) { - const tsConfig = resolve(projectDir, "src/backend/tsconfig.json"); - configProgram = TJS.programFromConfig(tsConfig, - sync(resolve(projectDir, "src/backend/common/infrastructure/config/**/*.ts")) - ); + return result; } - return configProgram; } -export const getTsConfigGenerator = (): TJS.JsonSchemaGenerator => { - if(generatorFromConfig === undefined) { - generatorFromConfig = buildSchemaGenerator(getTsConfigProgram()); - if(generatorFromConfig === null) { - throw new Error('Schema generator had errors! See console output.'); - } + +const tsjConfig: TSJCompletedConfig = { + ...DEFAULT_CONFIG, + sortProps: false, + additionalProperties: true, + markdownDescription: true, + path: resolve(projectDir, "src/backend/common/infrastructure/config/aioConfig.ts"), + tsconfig: resolve(projectDir, "src/backend/tsconfig.json"), +}; + +const formatter = createFormatter(tsjConfig, (fmt, circularReferenceTypeFormatter) => { + fmt.addTypeFormatter(new CustomLiteralTypeFormatter()); +}); + +let vegaGenerator: SchemaGenerator; + +export const createVegaGenerator = () => { + if(vegaGenerator === undefined) { + const program = createProgram(tsjConfig); + const parser = createParser(program, tsjConfig); + vegaGenerator = new SchemaGenerator(program, parser, formatter, tsjConfig); } - return generatorFromConfig; + return vegaGenerator; } -export const getTypeSchemaFromConfigGenerator = (type: string): TJS.Definition | null => { - return TJS.generateSchema(getTsConfigProgram(), type, undefined, [], getTsConfigGenerator()); +export const getTypeSchemaFromConfigGenerator = (type: string): any => { + const generator = createVegaGenerator(); + const schema = generator.createSchema(type) + return schema; } - -export const defaultGeneratorArgs: TJS.PartialArgs = { - required: true, - //ignoreErrors: true, - titles: true, - validationKeywords: ['deprecationMessage'], - constAsEnum: true, - ref: true, - esModuleInterop: true -};