diff --git a/config/subsonic.json.example b/config/subsonic.json.example index e26ebfd9..2e4415cb 100644 --- a/config/subsonic.json.example +++ b/config/subsonic.json.example @@ -5,7 +5,8 @@ "data": { "url": "http://localhost:4040/airsonic", "user": "yourUser", - "password": "yourPassword" + "password": "yourPassword", + "usersAllow": ["yourUser"] } } ] diff --git a/docsite/docs/configuration/configuration.mdx b/docsite/docs/configuration/configuration.mdx index 99030fb0..f30012a5 100644 --- a/docsite/docs/configuration/configuration.mdx +++ b/docsite/docs/configuration/configuration.mdx @@ -547,6 +547,8 @@ Can use this source for any application that implements the [Subsonic API](http: ::: +Use the optional `usersAllow` property with **File** or **AIO** configuration to restrict scrobbling to a list of defined users. + #### Configuration diff --git a/src/backend/common/infrastructure/config/source/subsonic.ts b/src/backend/common/infrastructure/config/source/subsonic.ts index 63a5999d..c79acda9 100644 --- a/src/backend/common/infrastructure/config/source/subsonic.ts +++ b/src/backend/common/infrastructure/config/source/subsonic.ts @@ -55,6 +55,13 @@ export interface SubsonicData extends CommonSourceData, PollingOptions { * @default false * */ legacyAuthentication?: boolean + + /** + * Only scrobble for specific users (case-insensitive) + * + * If undefined or an empty string/list MS will scrobble activity from all users + * */ + usersAllow?: string | string[] } export interface SubSonicSourceConfig extends CommonSourceConfig { data: SubsonicData diff --git a/src/backend/sources/SubsonicSource.ts b/src/backend/sources/SubsonicSource.ts index 6af5642b..559dbbbf 100644 --- a/src/backend/sources/SubsonicSource.ts +++ b/src/backend/sources/SubsonicSource.ts @@ -24,6 +24,8 @@ export class SubsonicSource extends MemorySource { declare config: SubSonicSourceConfig; + usersAllow: string[] = []; + constructor(name: any, config: SubSonicSourceConfig, internal: InternalConfig, emitter: EventEmitter) { const { data: { @@ -193,6 +195,22 @@ export class SubsonicSource extends MemorySource { throw new Error(`Cannot setup Subsonic source, 'url' is not defined`); } + let usersAllowVal = this.config.data.usersAllow; + if(usersAllowVal !== undefined && usersAllowVal !== null) { + if(!Array.isArray(usersAllowVal)) { + usersAllowVal = [usersAllowVal]; + } + if(usersAllowVal.filter(x => x.toString().trim() !== '').length > 0) { + this.usersAllow = usersAllowVal.map(x => x.toString().trim()); + } + } + + if(this.usersAllow.length === 0) { + this.logger.verbose('Will monitor plays by all users'); + } else { + this.logger.verbose(`Will only monitor plays for the following users: ${this.usersAllow.join(', ')}`); + } + return true; } @@ -245,7 +263,8 @@ export class SubsonicSource extends MemorySource { } = resp; // sometimes subsonic sources will return the same track as being played twice on the same player, need to remove this so we don't duplicate plays const deduped = removeDuplicates(entry.map(SubsonicSource.formatPlayObj)); - return this.processRecentPlays(deduped); + const userFiltered = this.usersAllow.length == 0 ? deduped : deduped.filter(x => x.meta.user === undefined || this.usersAllow.map(x => x.toLocaleLowerCase()).includes(x.meta.user.toLocaleLowerCase())); + return this.processRecentPlays(userFiltered); } }