Beispiel #1
0
 def volchange(self, val):
     if self.volumecontrol is not None:
         self.volumecontrol.change_volume_percent(val)
         report_usage("audiocontrol_powercontroller_volume", 1)
     else:
         logging.info(
             "no volume control, ignoring powercontroller feedback")
Beispiel #2
0
    def notify(self, metadata):
        """
        Scrobble metadata of last song, store meta data of the current song
        """

        if metadata is not None and metadata.sameSong(self.current_metadata):
            self.current_metadata = metadata
            logging.debug(
                "updated metadata for current song, not scrobbling now")
            return

        # Check if the last song was played at least 30 seconds, otherwise
        # don't scrobble it'
        now = time.time()
        listening_time = (now - self.starttime)
        lastsong_md = None

        if listening_time > 30:
            lastsong_md = self.current_metadata
        else:
            logging.debug("not yet logging %s, not listened for at least 30s",
                          lastsong_md)

        self.starttime = now
        logging.info("new song: %s", metadata)
        self.current_metadata = metadata

        if (lastsong_md is not None) and not (lastsong_md.is_unknown()):
            sender = ScrobbleSender(self.get_network(), lastsong_md)
            sender.start()
            report_usage("audiocontrol_lastfm_scrobble", 1)
        else:
            logging.info("no track data, not scrobbling %s", lastsong_md)
Beispiel #3
0
    def keyboard_hook(self, e):
        import keyboard

        if e.event_type == keyboard.KEY_DOWN:
            try:
                command = self.codetable[e.scan_code]
            except:
                logging.error("%s unknown", e.scan_code)
                return

            try:
                command_run = False
                if command == "volume_up":
                    if self.volumecontrol is not None:
                        self.volumecontrol.change_volume_percent(5)
                        command_run = True
                    else:
                        logging.info("ignoring %s, no volume control", command)

                elif command == "volume_down":
                    if self.volumecontrol is not None:
                        self.volumecontrol.change_volume_percent(-5)
                        command_run = True
                    else:
                        logging.info("ignoring %s, no volume control", command)

                elif command == "previous":
                    if self.playercontrol is not None:
                        self.playercontrol.previous()
                        command_run = True
                    else:
                        logging.info("ignoring %s, no playback control",
                                     command)

                elif command == "next":
                    if self.playercontrol is not None:
                        self.playercontrol.next()
                        command_run = True
                    else:
                        logging.info("ignoring %s, no playback control",
                                     command)

                elif command == "playpause":
                    if self.playercontrol is not None:
                        self.playercontrol.playpause()
                        command_run = True
                    else:
                        logging.info("ignoring %s, no playback control",
                                     command)

                if command_run:
                    report_usage("audiocontrol_keyboard_key", 1)

                logging.debug("processed %s", command)

            except Exception as e:
                logging.warning("problem handling %s (%s)", command, e)
Beispiel #4
0
    def set_ips(self, ip_list):
        if isinstance(ip_list, str):
            ips = []
            for ip in ip_list.split(","):
                ips.append(ip.strip())

            ip_list = ips

        self.urls = []
        for ip in ip_list:
            if len(ip) > 0:
                url = "https://{}:4343/api/v1/dev/widget/update/com.lametric.b647e225d0b81484c19ff25030915e58".format(
                    ip)
                self.urls.append(url)
                report_usage("audiocontrol_lametric_discovered", 1)
Beispiel #5
0
    def love(self, love):
        try:
            track = self.get_network().get_track(self.current_metadata.artist,
                                                 self.current_metadata.title)
            if love:
                logging.info("sending love to Last.FM")
                track.love()
                report_usage("audiocontrol_lastfm_love", 1)
            else:
                logging.info("sending unlove to Last.FM")
                track.unlove()
                report_usage("audiocontrol_lastfm_love", 1)
        except Exception as e:
            logging.warning("got exception %s while love/unlove", e)
            return False

        return True
Beispiel #6
0
    def notify(self, metadata):
        if metadata.artist is None or metadata.title is None:
            logging.debug("ignoring undefined metatdata")
            return

        data = {
            "frames": [{
                "text": metadata.artist + "-" + metadata.title,
                "icon": "a22046",
                "duration": 10000,
            }]
        }

        headers = {
            "X-Access-Token": ACCESS_TOKEN,
            "Accept": "application/json",
            "Cache-Control": "no-cache"
        }

        for url in self.urls:
            logging.info("sending update to LaMetric at %s", url)
            report_usage("audiocontrol_lametric_metadata", 1)

            post_data(url, json.dumps(data), headers=headers, verify=False)
Beispiel #7
0
 def playpause(self):
     if self.playercontrol is not None:
         self.playercontrol.playpause()
         report_usage("audiocontrol_powercontroller_button", 1)
     else:
         logging.info("no player control, ignoring press")
Beispiel #8
0
    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)
Beispiel #9
0
 def decrease(self,val):
     if self.volumecontrol is not None:
         self.volumecontrol.change_volume_percent(-self.step)
         report_usage("audiocontrol_rotary_volume", 1)
     else:
         logging.info("no volume control, ignoring rotary control")