This commit is contained in:
@@ -43,6 +43,11 @@ class HeosClient:
|
||||
self._sock = None
|
||||
self._buffer = b""
|
||||
self._lock = threading.Lock()
|
||||
# pid -> {"cur_pos", "duration"}, filled in from whatever
|
||||
# unsolicited progress events turn up while we are reading the
|
||||
# reply to some other command. Dropped on reconnect, since a gap
|
||||
# in the connection is a gap in what we know.
|
||||
self._progress = {}
|
||||
|
||||
# -- connection management -----------------------------------------
|
||||
def _connect(self):
|
||||
@@ -51,6 +56,14 @@ class HeosClient:
|
||||
sock.settimeout(self.timeout)
|
||||
self._sock = sock
|
||||
self._buffer = b""
|
||||
self._progress = {}
|
||||
# Without this, HEOS never pushes the now-playing-progress events
|
||||
# that _exchange() below watches for. Best-effort: a player that
|
||||
# refuses it still works, it just never shows song progress.
|
||||
try:
|
||||
self._exchange("system/register_for_change_events", {"enable": "on"})
|
||||
except (OSError, HeosError):
|
||||
pass
|
||||
|
||||
def _close(self):
|
||||
if self._sock is not None:
|
||||
@@ -106,6 +119,7 @@ class HeosClient:
|
||||
heos = reply.get("heos", {})
|
||||
|
||||
if heos.get("command") != path:
|
||||
self._watch_progress(heos)
|
||||
continue # an event or a late reply to something else
|
||||
if "under process" in heos.get("message", ""):
|
||||
continue # placeholder ack; the real payload follows
|
||||
@@ -113,6 +127,30 @@ class HeosClient:
|
||||
raise HeosError(_failure_text(heos))
|
||||
return reply
|
||||
|
||||
def _watch_progress(self, heos: dict):
|
||||
"""Skims a passing player_now_playing_progress event for its
|
||||
pid/cur_pos/duration, the only source of song-position data this
|
||||
client has -- there is no dedicated listener, so this only catches
|
||||
what happens to arrive while some other command is being read."""
|
||||
if heos.get("command") != "event/player_now_playing_progress":
|
||||
return
|
||||
message = parse_message(heos.get("message", ""))
|
||||
pid = message.get("pid")
|
||||
if not pid:
|
||||
return
|
||||
try:
|
||||
self._progress[pid] = {
|
||||
"cur_pos": int(message.get("cur_pos", 0)),
|
||||
"duration": int(message.get("duration", 0)),
|
||||
}
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def progress_for(self, pid) -> dict:
|
||||
"""{"cur_pos", "duration"} in ms for a player, or None if no
|
||||
progress event for it has come through yet this connection."""
|
||||
return self._progress.get(str(pid))
|
||||
|
||||
def heart_beat(self):
|
||||
"""Keep the socket warm so the first press after an idle spell is
|
||||
as fast as the rest."""
|
||||
|
||||
Reference in New Issue
Block a user