[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: Remove ttl from mb api to ensure primary/secondary ttl is used correctly

FoxxMD (Mar 30, 2026, 6:59 PM UTC) 7c8c185c 972eccd0

+7 -12
-1
src/backend/common/infrastructure/Atomic.ts
··· 294 294 url?: string 295 295 rateLimit?: [number, number] 296 296 contact: string, 297 - ttl?: string 298 297 apiKey?: string 299 298 requestTimeout?: number 300 299 }
+5 -9
src/backend/common/vendor/musicbrainz/MusicbrainzApiClient.ts
··· 45 45 escapeCharacters?: boolean 46 46 removeCharacters?: boolean, 47 47 using?: UsingTypes[] 48 - ttl?: string, 49 48 freetext?: boolean 50 49 } 51 50 ··· 61 60 super('Musicbrainz', name, config, options); 62 61 63 62 this.asyncStore = new AsyncLocalStorage(); 64 - this.cache = options.cache ?? getRoot().items.cache().cacheMetadata; 63 + this.cache = options.cache ?? getRoot().items.cache().cacheApi; 65 64 const mbMap = getRoot().items.mbMap(); 66 65 const mbApis: Record<string, MusicbrainzApiConfig> = {}; 67 66 for(const mbConfig of this.config.apis) { ··· 76 75 rateLimit: mbConfig.rateLimit ?? [1,1], 77 76 preRequest: options.logUrl === true || isDebugMode() ? (method, url, headers) => { 78 77 const cacheKey = this.asyncStore.getStore() ?? nanoid(); 79 - this.cache.set(`${cacheKey}-url`, `${method} - ${url}`, mbConfig.ttl ?? '1hr'); 78 + this.cache.set(`${cacheKey}-url`, `${method} - ${url}`); 80 79 if(mbConfig.apiKey !== undefined) { 81 80 headers.set('X-Api_key', mbConfig.apiKey); 82 81 } ··· 101 100 return 'API'; 102 101 } 103 102 104 - callApi = async <T = Response>(func: (mb: MusicBrainzApi) => Promise<any>, options?: { timeout?: number, ttl?: string, cacheKey?: string }): Promise<T> => { 103 + callApi = async <T = Response>(func: (mb: MusicBrainzApi) => Promise<any>, options?: { timeout?: number, cacheKey?: string }): Promise<T> => { 105 104 106 105 let apiConfig = this.rrApis.next().value; 107 106 108 107 const { 109 108 timeout = 30000, 110 - ttl = apiConfig.ttl ?? '1hr', 111 109 cacheKey 112 110 } = options || {}; 113 111 ··· 132 130 try { 133 131 const res = await this.callApiEndpoint(apiConfig.api, func, options); 134 132 if(cacheKey !== undefined) { 135 - await this.cache.set(cacheKey, res, ttl); 133 + await this.cache.set(cacheKey, res); 136 134 } 137 135 return res as T; 138 136 } catch (e) { ··· 202 200 escapeCharacters = true, 203 201 removeCharacters = false, 204 202 using = ['album','artist','title'], 205 - ttl, 206 203 freetext 207 204 } = options || {}; 208 205 ··· 311 308 312 309 313 310 this.logger.debug(`Search Query => ${q}`); 314 - this.cache.set(`${cacheKey}-qs`, q, '1hr'); 311 + this.cache.set(`${cacheKey}-qs`, q); 315 312 316 313 return mb.search('recording', { 317 314 query: q 318 315 }); 319 316 }, { 320 - ttl, 321 317 cacheKey 322 318 }); 323 319
+2 -2
src/backend/ioc.ts
··· 116 116 transformerManager.register({type: 'native', name: 'MSDefault'}); 117 117 } 118 118 119 - const metadataCache = (maybeSingletonCache !== undefined ? maybeSingletonCache : cacheFunc()).cacheMetadata; 120 - const coverArtApi = new CoverArtApiClient('', {}, {logger, cache: metadataCache}); 119 + const cacheApi = (maybeSingletonCache !== undefined ? maybeSingletonCache : cacheFunc()).cacheApi; 120 + const coverArtApi = new CoverArtApiClient('', {}, {logger, cache: cacheApi}); 121 121 122 122 const portVal: number | string = process.env.PORT ?? port; 123 123