import { logger } from 'yanl' ; import { NowPlayingTrack } from './types' ; import { SimpleEventEmitter } from './SimpleEventEmitter' ; enum State { Listening , Stopped } enum Events { Error = 'error' , TrackChanged = 'track-changed' , TrackStopped = 'track-stopped' } type EventListeners = { [ Events . Error ] ( error ) : void ; [ Events . TrackChanged ] ( track ) : void ; [ Events . TrackStopped ] ( ) : void ; } ; export abstract class SourceProvider < T = { } > extends SimpleEventEmitter < EventListeners > { public static Events = Events ; private state : State = State . Stopped ; private nextCheckTimeout ! : NodeJS . Timeout ; private lastTrack : NowPlayingTrack | null = null ; constructor ( protected options ) { super ( ) ; } public isListening ( ) { return this . state === State . Listening ; } public listen ( ) { if ( this . isListening ( ) ) { return ; } logger . debug ( 'started listening from source' ) ; this . state = State . Listening ; this . checkNowPlaying ( ) ; } public stop ( ) { logger . debug ( 'stopped listening from source' ) ; this . state = State . Stopped ; clearTimeout ( this . nextCheckTimeout ) ; } protected getNowPlaying ( ) { throw new Error ( `Method \`getNowPlaying\` is not implemented in ${ this . constructor . name }` ) ; } private async checkNowPlaying ( ) { logger . debug ( 'checking source for now playing track' ) ; let track = null ; try { track = await this . getNowPlaying ( ) ; } catch ( error ) { this . emit ( Events . Error , error ) ; return ; } if ( this . state === State . Stopped ) { return ; } if ( this . hasTrackChanged ( track ) ) { if ( track ) { this . emit ( Events . TrackChanged , track ) ; } else { this . emit ( Events . TrackStopped ) ; } this . lastTrack = track ; } this . nextCheckTimeout = setTimeout ( ( ) => this . checkNowPlaying ( ) , this . options . updateFrequency ) ; logger . debug ( 'scheduled next source check' ) ; } private hasTrackChanged ( track ) { const { lastTrack } = this ; if ( lastTrack == null || track == null ) { return lastTrack !== track ; } const keys = Object . keys ( track ) as Array < keyof NowPlayingTrack > ; return keys . some ( key => track [ key ] !== lastTrack [ key ] ) ; } }