Added configuration validation. Minor config change.

This commit is contained in:
Tom 2024-12-04 22:28:33 +00:00
parent 79b27b8e32
commit 1b91e330c1
6 changed files with 174 additions and 74 deletions

1
.gitignore vendored
View File

@ -2,4 +2,5 @@ node_modules/
logs/
config/*
!config/configuration.js
!config.schema.js
credentials.*

110
config/config.schema.js Normal file
View File

@ -0,0 +1,110 @@
const schema = {
type: 'object',
required: [],
properties: {
plex: {
type: 'object',
required: ['url', 'token'],
properties: {
url: {
type: 'string'
},
token: {
type: 'string'
},
filters: {
type: 'array',
minItems: 0,
items: {
type: 'object',
properties: {
library: {
type: 'array',
items: {
type: 'string'
},
minItems: 0,
},
ip: {
type: 'array',
items: {
type: 'string'
},
minItems: 0,
},
deviceId: {
type: 'array',
items: {
type: 'string'
},
minItems: 0,
},
platform: {
type: 'array',
items: {
type: 'string'
},
minItems: 0,
},
product: {
type: 'array',
items: {
type: 'string'
},
minItems: 0,
},
}
}
}
}
},
scrobble: {
type: 'object',
properties: {
minimum: {
type: 'object',
properties: {
percent: {
type: 'number'
},
duration: {
type: 'number'
}
}
}
}
},
spotify: {
type: 'object',
required: ['client_id', 'client_secret', 'redirect_uri'],
properties: {
client_id: {
type: 'string'
},
client_secret: {
type: 'string'
},
redirect_uri: {
type: 'string'
}
}
},
web: {
type: 'object',
required: [],
properties: {
host: {
type: 'string'
},
port: {
type: 'number'
}
}
}
}
}
module.exports = schema;

View File

@ -1,26 +1,19 @@
const config = require('config');
const Ajv = require("ajv");
const fs = require("fs");
const logger = require("../services/logging");
const yaml = require("js-yaml");
const configuration = {
const configurationBase = {
plex: {
url: null,
token: null
token: null,
filters: [] // { library, ip, deviceId, platform, product }
},
scrobble: {
minimum: {
percent: null,
duration: null
},
plex: {
delay: null,
filters: []
/* A filter will have the following properties:
library: [""],
ip: [""],
deviceId: [""],
platform: [""],
product: [""]
*/
},
},
spotify: {
client_id: null,
@ -33,27 +26,18 @@ const configuration = {
}
};
if (config.has("plex.url"))
configuration.plex.url = config.get("plex.url");
if (config.has("plex.token"))
configuration.plex.token = config.get("plex.token");
const configurationFile = yaml.load(fs.readFileSync('config/config.yml'), yaml.JSON_SCHEMA);
const configuration = { ...configurationBase, ...configurationFile }
if (config.has("scrobble.plex.delay"))
configuration.scrobble.plex.delay = config.get("scrobble.plex.delay");
if (config.has("scrobble.plex.filters"))
configuration.scrobble.plex.filters = config.get("scrobble.plex.filters");
const ajv = new Ajv({ allErrors: true });
const schema = require("./config.schema");
const { exit } = require("process");
const validation = ajv.compile(schema);
const valid = validation(configurationFile);
if (config.has("scrobble.minimum.duration"))
configuration.scrobble.minimum.duration = config.get("scrobble.minimum.duration");
if (config.has("scrobble.minimum.percent"))
configuration.scrobble.minimum.percent = config.get("scrobble.minimum.percent");
if (config.has("spotify"))
configuration.spotify = config.get("spotify");
if (config.has("web.host"))
configuration.web.host = config.get("web.host");
if (config.has("web.port"))
configuration.web.port = config.get("web.port");
if (!valid) {
logger.error("Configuration is invalid. " + validation.errors.map(e => e.message).join(". ") + ".");
(async () => { await new Promise(resolve => setTimeout(resolve, 1000)); exit(1); })();
}
module.exports = configuration;

80
package-lock.json generated
View File

@ -9,9 +9,8 @@
"version": "0.0.0",
"license": "ISC",
"dependencies": {
"ajv": "^8.17.1",
"axios": "^1.7.8",
"config": "^3.3.12",
"dotenv": "^16.4.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.1",
"helmet": "^8.0.0",
@ -32,6 +31,22 @@
"node": ">= 0.6"
}
},
"node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -134,18 +149,6 @@
"node": ">= 0.8"
}
},
"node_modules/config": {
"version": "3.3.12",
"resolved": "https://registry.npmjs.org/config/-/config-3.3.12.tgz",
"integrity": "sha512-Vmx389R/QVM3foxqBzXO8t2tUikYZP64Q6vQxGrsMpREeJc/aWRnPRERXWsYzOHAumx/AOoILWe6nU3ZJL+6Sw==",
"license": "MIT",
"dependencies": {
"json5": "^2.2.3"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -236,18 +239,6 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dotenv": {
"version": "16.4.6",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.6.tgz",
"integrity": "sha512-JhcR/+KIjkkjiU8yEpaB/USlzVi3i5whwOjpIRNGi9svKEXZSe+Qp6IWAjFjv+2GViAoDRCUv/QLNziQxsLqDg==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -356,6 +347,12 @@
"express": "4 || 5 || ^5.0.0-beta.1"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/fast-redact": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz",
@ -365,6 +362,12 @@
"node": ">=6"
}
},
"node_modules/fast-uri": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
"integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
"license": "BSD-3-Clause"
},
"node_modules/finalhandler": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
@ -593,17 +596,11 @@
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/media-typer": {
"version": "0.3.0",
@ -844,6 +841,15 @@
"node": ">= 12.13.0"
}
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",

View File

@ -9,9 +9,8 @@
"license": "ISC",
"description": "",
"dependencies": {
"ajv": "^8.17.1",
"axios": "^1.7.8",
"config": "^3.3.12",
"dotenv": "^16.4.6",
"express": "^4.21.1",
"express-rate-limit": "^7.4.1",
"helmet": "^8.0.0",

View File

@ -78,7 +78,7 @@ function checkIfCanScrobble(current, previous, now) {
let filters = [];
if (previous.source == 'plex')
filters = config.scrobble.plex.filters;
filters = config.plex.filters;
if (!applyFilter(previous, filters)) {
logger.debug(previous, 'No filters got triggered. Ignoring.');