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

feat: Implement live client/source status updates

FoxxMD (Oct 19, 2023, 11:53 AM EDT) 3aab6a20 49e9fd4b

+22
+3
src/backend/scrobblers/AbstractScrobbleClient.ts
··· 510 510 protected doStopScrobbling = (reason: string = 'system') => { 511 511 this.scrobbling = false; 512 512 this.userScrobblingStopSignal = undefined; 513 + this.emitEvent('statusChange', {status: 'Idle'}); 513 514 this.logger.info(`Stopped scrobble processing due to: ${reason}`); 514 515 } 515 516 ··· 520 521 return true; 521 522 } 522 523 this.logger.info('Scrobble processing started'); 524 + this.emitEvent('statusChange', {status: 'Running'}); 523 525 524 526 try { 525 527 this.scrobbling = true; ··· 563 565 } catch (e) { 564 566 this.logger.error('Scrobble processing interrupted'); 565 567 this.logger.error(e); 568 + this.emitEvent('statusChange', {status: 'Idle'}); 566 569 this.scrobbling = false; 567 570 throw e; 568 571 }
+3
src/backend/sources/AbstractSource.ts
··· 330 330 protected doStopPolling = (reason: string = 'system') => { 331 331 this.polling = false; 332 332 this.userPollingStopSignal = undefined; 333 + this.emitEvent('statusChange', {status: 'Idle'}); 333 334 this.logger.info(`Stopped polling due to: ${reason}`); 334 335 } 335 336 ··· 340 341 return true; 341 342 } 342 343 this.logger.info('Polling started'); 344 + this.emitEvent('statusChange', {status: 'Running'}); 343 345 this.notify({title: `${this.identifier} - Polling Started`, message: 'Polling Started', priority: 'info'}); 344 346 this.lastActivityAt = dayjs(); 345 347 let checkCount = 0; ··· 416 418 } catch (e) { 417 419 this.logger.error('Error occurred while polling'); 418 420 this.logger.error(e); 421 + this.emitEvent('statusChange', {status: 'Idle'}); 419 422 this.polling = false; 420 423 throw e; 421 424 }
+16
src/client/status/ducks.ts
··· 66 66 } 67 67 } 68 68 ) 69 + .addMatcher( 70 + (action) => sourceUpdate.match(action) && action.payload.event === 'statusChange', 71 + (state, action) => { 72 + if(state.entities[action.payload.id] !== undefined) { 73 + state.entities[action.payload.id].status = action.payload.data.status; 74 + } 75 + } 76 + ) 69 77 } 70 78 }); 71 79 const clientSlice = createSlice({ ··· 95 103 (state, action) => { 96 104 if(state.entities[action.payload.id] !== undefined) { 97 105 state.entities[action.payload.id].deadLetterScrobbles = state.entities[action.payload.id].deadLetterScrobbles + 1; 106 + } 107 + } 108 + ) 109 + .addMatcher( 110 + (action) => clientUpdate.match(action) && action.payload.event === 'statusChange', 111 + (state, action) => { 112 + if(state.entities[action.payload.id] !== undefined) { 113 + state.entities[action.payload.id].status = action.payload.data.status; 98 114 } 99 115 } 100 116 )