[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.

fix: Fix typing for play update events

FoxxMD (Jun 24, 2026, 1:10 AM UTC) 94d3ea5d e998006e

+8 -5
+1 -1
src/backend/common/AbstractComponent.ts
··· 549 549 }); 550 550 } 551 551 552 - protected emitComponentUpdate = (payload: Partial<typeof this.getApiData>) => { 552 + protected emitComponentUpdate = <T = Partial<typeof this.getApiData>>(payload: T) => { 553 553 this.emitEvent('componentUpdate', payload); 554 554 } 555 555 protected emitPlayUpdate = (payload: MarkRequired<Partial<PlayApiCommonDetailed>, 'uid'>) => {
+6 -3
src/backend/scrobblers/AbstractScrobbleClient.ts
··· 1185 1185 const queueState = currQueuedPlay.queueStates.find(x => x.queueName === CLIENT_INGRESS_QUEUE); 1186 1186 if(queueError !== undefined) { 1187 1187 await this.queueRepo.updateById(queueState.id, {queueStatus: 'failed', error: queueError}); 1188 + queueState.queueStatus = 'failed'; 1189 + queueState.error = queueError; 1188 1190 await this.playRepo.updateById(currQueuedPlay.id, {state: 'failed', error: queueError, play: currQueuedPlay.play}); 1189 1191 currQueuedPlay.state = 'failed'; 1190 1192 currQueuedPlay.error = queueError; ··· 1192 1194 await this.queueRepo.updateById(queueState.id, {queueStatus: 'completed'}); 1193 1195 await this.playRepo.updateById(currQueuedPlay.id, {state: successState ?? 'scrobbled', play: currQueuedPlay.play}); 1194 1196 currQueuedPlay.state = successState ?? 'scrobbled'; 1197 + queueState.queueStatus = 'completed'; 1195 1198 } 1196 - this.emitPlayUpdate(currQueuedPlay); 1199 + this.emitPlayUpdate({...currQueuedPlay, queueStates: [queueState]} as unknown as PlayApiCommonDetailed); 1197 1200 this.emitEvent('scrobbleDequeued', { queuedScrobble: currQueuedPlay }) 1198 1201 this.queuedGauge.labels(this.getPrometheusLabels()).dec(); 1199 1202 this.queuedLength -= 1; ··· 1496 1499 }); 1497 1500 1498 1501 const playRow = await this.playRepo.createPlays([createPlayData]); 1499 - await this.queueRepo.create({componentId: this.dbComponent.id, playId: playRow[0].id, queueName: CLIENT_INGRESS_QUEUE}); 1502 + const queueState = await this.queueRepo.create({componentId: this.dbComponent.id, playId: playRow[0].id, queueName: CLIENT_INGRESS_QUEUE}); 1500 1503 createdQueuedPlays.push(playRow[0]); 1501 1504 this.logger.debug(`Added ${buildTrackString(play)} to the queue`); 1502 1505 this.setStatus(`Added Play from parent ${play.uid} to queue`); ··· 1504 1507 const queuedPlay = {id: nanoid(), source, play: play} 1505 1508 //await this.playRepo.updateById(play.meta.dbId, {play}); 1506 1509 this.emitEvent('scrobbleQueued', {queuedPlay: queuedPlay}); 1507 - this.emitPlayInsert(playRow[0]); 1510 + this.emitPlayInsert({...playRow[0], queueStates: [queueState]} as unknown as PlayApiCommonDetailed); 1508 1511 this.queuedLength += 1; 1509 1512 //this.queuedScrobbles.push(queuedPlay); 1510 1513 this.queuedGauge.labels(this.getPrometheusLabels()).inc();
+1 -1
src/backend/sources/AbstractSource.ts
··· 334 334 this.tracksDiscovered++; 335 335 this.logger.info(`Discovered => ${buildTrackString(play)}`); 336 336 this.emitEvent('discovered', {play}); 337 - this.emitPlayInsert(playRow); 337 + this.emitPlayInsert({...playRow[0], queueStates: []} as unknown as PlayApiCommonDetailed); 338 338 this.discoveredCounter.labels(this.getPrometheusLabels()).inc(); 339 339 play.id = playRow[0].id; 340 340 play.uid = playRow[0].uid;