def update_listitem(self, listitem, type, id, market='SE'): if type == 'Podcast': info = self.get_endpoint(SPOTIFY_ENDPOINT_EPISODES, id, market) album = get( info, ['show', 'name'], 'unknown show', ) artist = get(info, ['show', 'publisher'], 'unknown publisher') thumb = get(info, ['images', 0, 'url'], ADDON_ICON) title = get(info, ['name'], 'unknown episode') elif type == 'Track': info = self.get_endpoint(SPOTIFY_ENDPOINT_TRACKS, id, market) album = get(info, ['album', 'name'], 'unknown album') artist = get(info, ['artists', 0, 'name'], 'unknown artist') thumb = get(info, ['album', 'images', 0, 'url'], ADDON_ICON) title = get(info, ['name'], 'unknown title') else: album = '' artist = 'Unknown Media Type' thumb = ADDON_ICON title = '' listitem.setArt(dict(fanart=thumb, thumb=thumb)) listitem.setInfo('music', dict(album=album, artist=artist, title=title)) log('{}#{}#{}#{}'.format(title, artist, album, thumb))
def load_modules(self): args = [module[2] for module in self.list_modules()] for module in [self.null_sink, self.rtp_send]: if module['args'] not in args: run('pactl load-module {} {}'.format(module['module'], module['args'])) log('loaded {} {}'.format(module['module'], module['args'])) self.suspend_sink(1)
def onPlayBackStopped(self): if self.is_playing_librespot: log('librespot playback stopped') self.is_playing_librespot = False self.stop_librespot(True) else: log('Kodi playback stopped') self.start_librespot()
def get_headers(self): if time.time() > self.expiration: log('token expired') token = requests.post(**SPOTIFY_REQUEST_TOKEN).json() log(token) self.expiration = time.time() + float(token['expires_in']) - 5 self.headers['Authorization'] = 'Bearer {}'.format( token['access_token'])
def get_endpoint(self, endpoint, id, market): try: self.get_headers() return requests.get(url=endpoint + id, headers=self.headers, params=dict(market=market)).json() except Exception as e: log('failed to get {} from Spotify {}'.format(endpoint, e)) return {}
def __init__(self): super().__init__() settings = get_settings() quoted = {k: shlex.quote(v) for (k, v) in settings.items()} command = LIBRESPOT if settings['autoplay'] == 'true': command += LIBRESPOT_AUTOPLAY if (settings['discovery'] == 'false' and settings['password'] != '' and settings['username'] != ''): command += LIBRESPOT_AUTHENTICATE self.command = shlex.split(command.format(**quoted)) log(shlex.split(command.format(**dict(quoted, password='******')))) self.is_aborted = False self.is_dead = False self.pulseaudio = Pulseaudio(settings) self.listitem = xbmcgui.ListItem() self.listitem.addStreamInfo('audio', {'codec': CODEC}) self.listitem.setPath(path=self.pulseaudio.url)
def run(self): log('monitor started') is_aborted = False is_dead = False while not (is_aborted or is_dead): self.is_changed = False librespot = Librespot() with librespot: while True: is_aborted = self.waitForAbort(1) if is_aborted: log('monitor aborted') librespot.is_aborted = True break is_dead = librespot.is_dead if is_dead: log('librespot died') notification('Too many errors') break if self.is_changed: log('settings changed') break log('monitor stopped')
def on_event_playing(self, type, id): log('event playing') SPOTIFY.update_listitem(self.listitem, type, id, self.country) if not self.isPlaying(): log('starting librespot playback') self.pulseaudio.suspend_sink(0) self.play(self.pulseaudio.url, self.listitem) elif self.is_playing_librespot: log('updating librespot playback') self.updateInfoTag(self.listitem)
def unload_modules(self): for module in self.list_modules(): if module[2] in [self.null_sink['args'], self.rtp_send['args']]: run('pactl unload-module {}'.format(module[0])) log('unloaded {} {}'.format(module[1], module[2]))
def suspend_sink(self, bit): run(self.suspend.format(bit)) log('suspended sink {}'.format(bit))
def onPlayBackStarted(self): log('Kodi playback started') self.is_playing_librespot = self.getPlayingFile() == self.pulseaudio.url if not self.is_playing_librespot: self.stop_librespot()
def on_event_stopped(self): self.pulseaudio.suspend_sink(1) log('event stopped') self.panics = 0 self.stop()
def on_event_panic(self): self.pulseaudio.suspend_sink(1) self.panics += 1 log('event panic {}/{}'.format(self.panics, MAX_PANICS)) self.is_dead = self.panics >= MAX_PANICS self.stop_librespot(True)
def stop(self): if self.is_playing_librespot and not self.is_aborted: log('stopping librespot playback') self.is_playing_librespot = False super().stop()
def run_librespot(self): log('librespot thread started') self.restart = True while self.restart and not self.is_dead: self.librespot = subprocess.Popen( self.command, cwd=ADDON_HOME, env=ADDON_ENVT, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, text=True) log('librespot started') with self.librespot.stdout: for line in self.librespot.stdout: words = line.split() if words[0] == '@Playing': self.on_event_playing(words[1], words[2]) elif words[0] == '@Stopped': self.on_event_stopped() elif words[0] == 'stack': self.on_event_panic() else: log(line.rstrip()) if 'Country:' in line: self.country = words[-1].strip('"') log('country={}'.format(self.country)) self.pulseaudio.suspend_sink(1) self.stop() self.librespot.wait() log('librespot stopped') self.librespot = None log('librespot thread stopped')