[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
0

Configure Feed

Select the types of activity you want to include in your feed.

refactor(config)!: Move remaining common options out of source data and into options

* Move logPayload and logFilterFailure to options
* Disallow use of "options" property in common data

FoxxMD (May 10, 2024, 12:38 PM EDT) 3dc9e7d8 ab372b83

+35 -116
+10 -12
config/config.json.example
··· 2 2 "debugMode": false, 3 3 "disableWeb": false, 4 4 "sourceDefaults": { 5 - "options": { 6 - "logPayload": false, 7 - "logFilterFailure": "warn", 8 - "logPlayerState": false, 9 - "scrobbleThresholds": { 10 - "duration": 30, 11 - "percent": 50 12 - }, 13 - "maxPollRetries": 1, 14 - "maxRequestRetries": 1, 15 - "retryMultiplier": 1.5 16 - } 5 + "logPayload": false, 6 + "logFilterFailure": "warn", 7 + "logPlayerState": false, 8 + "scrobbleThresholds": { 9 + "duration": 30, 10 + "percent": 50 11 + }, 12 + "maxPollRetries": 1, 13 + "maxRequestRetries": 1, 14 + "retryMultiplier": 1.5 17 15 }, 18 16 "clientDefaults": { 19 17 "maxRequestRetries": 1,
+2
docsite/docs/configuration/kitchensink.md
··· 42 42 "data": { 43 43 "clientId": "foxxSpotifyAppId", 44 44 "clientSecret": "foxxSpotifyAppSecret", 45 + }, 46 + "options": { 45 47 "maxRequestRetries": 2, // override default max retries because spotify can...spotty 46 48 } 47 49 },
+2
src/backend/common/infrastructure/Atomic.ts
··· 195 195 } 196 196 197 197 export type AbstractApiOptions = Record<any, any> & { logger: Logger } 198 + 199 + export type keyOmit<T, U extends keyof any> = T & { [P in U]?: never }
+3 -7
src/backend/common/infrastructure/config/aioConfig.ts
··· 2 2 import { ClientAIOConfig } from "./client/clients.js"; 3 3 import { RequestRetryOptions } from "./common.js"; 4 4 import { WebhookConfig } from "./health/webhooks.js"; 5 - import { CommonSourceOptions, ScrobbleThresholds, SourceRetryOptions } from "./source/index.js"; 5 + import { CommonSourceOptions, SourceRetryOptions } from "./source/index.js"; 6 6 import { SourceAIOConfig } from "./source/sources.js"; 7 7 8 8 9 - export interface SourceDefaults extends SourceRetryOptions { 10 - /** 11 - * 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. 12 - * */ 13 - scrobbleThresholds?: ScrobbleThresholds 14 - options?: CommonSourceOptions 9 + export interface SourceDefaults extends CommonSourceOptions { 15 10 } 11 + 16 12 export interface AIOConfig { 17 13 sourceDefaults?: SourceDefaults 18 14 clientDefaults?: RequestRetryOptions
+3 -4
src/backend/common/infrastructure/config/common.ts
··· 1 + import { keyOmit } from "../Atomic.js"; 2 + 1 3 export interface CommonConfig { 2 4 name?: string 3 5 data?: CommonData ··· 10 12 enable?: boolean 11 13 } 12 14 13 - export interface CommonData { 14 - [key: string]: any 15 - options?: Record<string, any> 16 - } 15 + export type CommonData = keyOmit<{ [key: string]: any }, "options"> 17 16 18 17 export interface RequestRetryOptions { 19 18 /**
-27
src/backend/common/infrastructure/config/source/jellyfin.ts
··· 17 17 * @examples [["MyServerName1"]] 18 18 * */ 19 19 servers?: string | string[] 20 - 21 - /** 22 - * Additional options for jellyfin logging and tuning 23 - * */ 24 - options?: { 25 - /** 26 - * Log raw Jellyfin webhook payload to debug 27 - * 28 - * @default false 29 - * @examples [false] 30 - * */ 31 - logPayload?: boolean 32 - 33 - /** 34 - * How MS should log when a Jellyfin event fails a defined filter (users/servers) 35 - * 36 - * * `false` => do not log 37 - * * `debug` => log to DEBUG level 38 - * * `warn` => log to WARN level (default) 39 - * 40 - * Hint: This is useful if you are sure this source is setup correctly and you have multiple other Jellyfin sources. Set to `debug` or `false` to reduce log noise. 41 - * 42 - * @default warn 43 - * @examples ["warn"] 44 - * */ 45 - logFilterFailure?: false | 'debug' | 'warn' 46 - } 47 20 } 48 21 49 22 export interface JellySourceConfig extends CommonSourceConfig {
-20
src/backend/common/infrastructure/config/source/plex.ts
··· 25 25 * @examples [["MyServerName"]] 26 26 * */ 27 27 servers?: string | string[] 28 - 29 - /** 30 - * Additional options for Plex/Tautulli logging and tuning 31 - * */ 32 - options?: { 33 - 34 - /** 35 - * How MS should log when a Plex/Tautulli event fails a defined filter (users/servers) 36 - * 37 - * * `false` => do not log 38 - * * `debug` => log to DEBUG level 39 - * * `warn` => log to WARN level (default) 40 - * 41 - * Hint: This is useful if you are sure this source is setup correctly and you have multiple other Plex/Tautulli sources. Set to `debug` or `false` to reduce log noise. 42 - * 43 - * @default warn 44 - * @examples ["warn"] 45 - * */ 46 - logFilterFailure?: false | 'debug' | 'warn' 47 - } 48 28 } 49 29 50 30 export interface PlexSourceConfig extends CommonSourceConfig {
-25
src/backend/common/infrastructure/config/source/webscrobbler.ts
··· 32 32 * @examples [["mixcloud","soundcloud","bandcamp"]] 33 33 * */ 34 34 whitelist?: string | string[] 35 - 36 - /** 37 - * Additional options for WebScrobbler logging and tuning 38 - * */ 39 - options?: { 40 - /** 41 - * Log raw WebScrobbler webhook payload to debug 42 - * 43 - * @default false 44 - * @examples [false] 45 - * */ 46 - logPayload?: boolean 47 - 48 - /** 49 - * How MS should log when a WebScrobbler event fails a defined filter 50 - * 51 - * * `false` => do not log 52 - * * `debug` => log to DEBUG level 53 - * * `warn` => log to WARN level (default) 54 - * 55 - * @default warn 56 - * @examples ["warn"] 57 - * */ 58 - logFilterFailure?: false | 'debug' | 'warn' 59 - } 60 35 } 61 36 62 37 export interface WebScrobblerSourceConfig extends CommonSourceConfig {
+7 -9
src/backend/sources/JellyfinSource.ts
··· 38 38 super('jellyfin', name, config, internal, emitter); 39 39 const { 40 40 data: { 41 - users, 42 - servers, 41 + users, 42 + servers, 43 + } = {}, 43 44 options: { 44 - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') 45 - } = {} 45 + logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') 46 46 } = {} 47 - } = config; 47 + } = this.config; 48 48 49 49 if(logFilterFailure !== false && !['debug', 'warn'].includes(logFilterFailure)) { 50 50 this.logger.warn(`logFilterFailure value of '${logFilterFailure.toString()}' is NOT VALID. Logging will not occur if filters fail. You should fix this.`); ··· 185 185 186 186 protected logFilterFailure = (str: string, meta?: any) => { 187 187 const { 188 - data: { 189 - options: { 190 - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') 191 - } = {} 188 + options: { 189 + logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') 192 190 } = {} 193 191 } = this.config; 194 192
+6 -8
src/backend/sources/PlexSource.ts
··· 28 28 user = [], 29 29 libraries = [], 30 30 servers = [], 31 - options: { 32 - logFilterFailure = 'warn' 33 - } = {} 34 31 } = {}, 35 - } = config 32 + options: { 33 + logFilterFailure = 'warn' 34 + } = {} 35 + } = this.config 36 36 37 37 if(logFilterFailure !== false && !['debug', 'warn'].includes(logFilterFailure)) { 38 38 this.logger.warn(`logFilterFailure value of '${logFilterFailure.toString()}' is NOT VALID. Logging will not occur if filters fail. You should fix this.`); ··· 134 134 135 135 protected logFilterFailure = (str: string, meta?: any) => { 136 136 const { 137 - data: { 138 - options: { 139 - logFilterFailure = 'warn' 140 - } = {} 137 + options: { 138 + logFilterFailure = 'warn' 141 139 } = {} 142 140 } = this.config; 143 141
+2 -4
src/backend/sources/ScrobbleSources.ts
··· 470 470 this.logger.warn(`${type} (${name}) source was disabled by config`); 471 471 return; 472 472 } 473 - 473 + 474 474 // add defaults 475 - const {options: defaultOptions = {}, ...restDefaults} = defaults; 476 - const data = {...defaults, ...d}; 477 - const compositeConfig: SourceConfig = {...clientConfig, data, options: {...defaultOptions, ...clientOptions}}; 475 + const compositeConfig: SourceConfig = {...clientConfig, data: d, options: {...defaults, ...clientOptions}}; 478 476 479 477 this.logger.debug(`(${name}) Constructing ${type} source`); 480 478 let newSource: AbstractSource;