def test_same_song(self): md1=Metadata("artist1","song1") md2=Metadata("artist1","song1", albumTitle="album1") md3=Metadata("artist1","song1", albumTitle="album2") md4=Metadata("artist2","song1") md5=Metadata("","song1") self.assertTrue(md1.sameSong(md2)) self.assertTrue(md1.sameSong(md3)) self.assertTrue(md2.sameSong(md3)) self.assertFalse(md1.sameSong(md4)) self.assertFalse(md1.sameSong(md5))
def main_loop(self): """ Main loop: - monitors state of all players - pauses players if a new player starts playback """ finished = False md = Metadata() active_players = [] MAX_FAIL = 3 # Workaround for spotifyd problems # spotify_stopped = 0 # Workaround for squeezelite mute squeezelite_active = 0 previous_state = "" ts = datetime.datetime.now() while not (finished): additional_delay = 0 new_player_started = None metadata_notified = False playing = False new_song = False state = "unknown" last_ts = ts ts = datetime.datetime.now() duration = (ts - last_ts).total_seconds() for p in self.all_players(): if self.playername(p) in self.ignore_players: continue if p not in self.state_table: ps = PlayerState() ps.supported_commands = self.get_supported_commands(p) logging.debug("Player %s supports %s", p, ps.supported_commands) self.state_table[p] = ps thisplayer_state = "unknown" try: thisplayer_state = self.get_player_state(p).lower() self.state_table[p].failed = 0 except: logging.info("Got no state from " + p) state = "unknown" self.state_table[p].failed = \ self.state_table[p].failed + 1 if self.state_table[p].failed >= MAX_FAIL: playername = self.playername(p) logging.warning("%s failed, trying to restart", playername) watchdog.restart_service(playername) self.state_table[p].failed = 0 self.state_table[p].state = thisplayer_state # Check if playback started on a player that wasn't # playing before if thisplayer_state == STATE_PLAYING: playing = True state = "playing" # if self.playername(p) == SPOTIFY_NAME: # spotify_stopped = 0 if self.playername(p) == LMS_NAME: squeezelite_active = 2 report_usage( "audiocontrol_playing_{}".format(self.playername(p)), duration) md = self.get_meta(p) if (p not in active_players): new_player_started = p active_players.insert(0, p) md.playerState = thisplayer_state # MPRIS delivers only very few metadata, these will be # enriched with external sources if (md.sameSong(self.metadata)): md.fill_undefined(self.metadata) else: new_song = True self.state_table[p].metadata = md if not (md.sameSong(self.metadata)): logging.debug("updated metadata: \nold %s\nnew %s", self.metadata, md) # Store this as "current" with self.metadata_lock: self.metadata = md self.metadata_notify(md) logging.debug("notifications about new metadata sent") elif state != previous_state: logging.debug("changed state to playing") self.metadata_notify(md) # Some players deliver artwork after initial metadata if md.artUrl != self.metadata.artUrl: logging.debug("artwork changes from %s to %s", self.metadata.artUrl, md.artUrl) self.metadata_notify(md) # Add metadata if this is a new song if new_song: enrich_metadata_bg(md, callback=self) logging.debug("metadata updater thread started") # Even if we din't send metadata, this is still # flagged metadata_notified = True else: # always keep one player in the active_players # list if len(active_players) > 1: if p in active_players: active_players.remove(p) # update metadata for stopped players from time to time i = randint(0, 600) if (i == 0): md = self.get_meta(p) md.playerState = thisplayer_state self.state_table[p].metadata = md self.playing = playing # Find active (or last paused) player if len(active_players) > 0: self.active_player = active_players[0] else: self.active_player = None # # Workaround for wrong state messages by Spotify # # Assume Spotify is still playing for 10 seconds if it's the # # active (or last stopped) player # if self.playername(self.active_player) == SPOTIFY_NAME: # # Less aggressive metadata polling on Spotify as each polling will # # result in an API request # additional_delay = 4 # if not(playing): # spotify_stopped += 1 + additional_delay # if spotify_stopped < 26: # if (spotify_stopped % 5) == 0: # logging.debug("spotify workaround %s", spotify_stopped) # playing = True # # Workaround for LMS muting the output after stopping the # player if self.volume_control is not None: if self.playername(self.active_player) != LMS_NAME: if squeezelite_active > 0: squeezelite_active = squeezelite_active - 1 logging.debug( "squeezelite was active before, unmuting") self.volume_control.set_mute(False) if not (playing) and squeezelite_active > 0: squeezelite_active = squeezelite_active - 1 logging.debug("squeezelite was active before, unmuting") self.volume_control.set_mute(False) # There might be no active player, but one that is paused # or stopped if not (playing) and len(active_players) > 0: p = active_players[0] md = self.get_meta(p) md.playerState = self.state_table[p].state state = md.playerState if state != previous_state: logging.debug("state transition %s -> %s", previous_state, state) if not metadata_notified: self.metadata_notify(md) for sd in self.state_displays: sd.update_playback_state(state) previous_state = state if new_player_started is not None: if self.auto_pause: logging.info( "new player %s started, pausing other active players", self.playername(active_players[0])) self.pause_inactive(new_player_started) else: logging.debug("auto-pause disabled") self.last_update = datetime.datetime.now() time.sleep(self.loop_delay + additional_delay)