MPD and Scene fixes + twitch-bot cleanup
This commit is contained in:
@@ -12,7 +12,12 @@ needs zero changes:
|
||||
{ _type, index, total, title, artist, trackTitle, album, year, genre,
|
||||
file, currentTime, duration, paused,
|
||||
nextTitle, nextArtist, nextTrackTitle, nextFile, nextTitles,
|
||||
coverPath, coverHash }
|
||||
coverPath, coverHash,
|
||||
audio: { format, samplerate, bits, channels, bitrate } }
|
||||
File-level audio info comes from MPD `status` (`audio` is "rate:bits:ch",
|
||||
`bitrate` is kbps) and the file extension (FORMAT label — FLAC/MP3/OPUS/…).
|
||||
Lossless tracks (FLAC, ALAC, WAV) report their actual bit depth; MP3/Opus
|
||||
report their decode word size, which is informational only.
|
||||
Next-track fields are populated when MPD reports `nextsong` in its status.
|
||||
`nextTitles` is up to 3 display strings peeked from the queue starting at
|
||||
the current song's successor — used by the Music Box overlay to show
|
||||
@@ -158,6 +163,72 @@ def _status_volume(status: dict) -> int | None:
|
||||
return volume if volume >= 0 else None
|
||||
|
||||
|
||||
# Map file extension → display label. Anything not listed falls through to
|
||||
# the uppercased extension so unusual codecs still render something readable.
|
||||
_FORMAT_LABELS = {
|
||||
"flac": "FLAC",
|
||||
"mp3": "MP3",
|
||||
"opus": "OPUS",
|
||||
"ogg": "OGG",
|
||||
"oga": "OGG",
|
||||
"m4a": "AAC",
|
||||
"mp4": "AAC",
|
||||
"aac": "AAC",
|
||||
"wav": "WAV",
|
||||
"wv": "WAVPACK",
|
||||
"ape": "APE",
|
||||
"alac": "ALAC",
|
||||
"webm": "WEBM",
|
||||
"wma": "WMA",
|
||||
}
|
||||
|
||||
|
||||
def _detect_format(uri: str | None) -> str | None:
|
||||
if not uri:
|
||||
return None
|
||||
ext = Path(uri).suffix.lower().lstrip(".")
|
||||
if not ext:
|
||||
return None
|
||||
return _FORMAT_LABELS.get(ext, ext.upper())
|
||||
|
||||
|
||||
def _parse_audio(audio_str: str | None) -> tuple[int | None, int | None, int | None]:
|
||||
"""Decode MPD's `audio` status string `samplerate:bits:channels`.
|
||||
`bits` may be `f` (float) or `dsd<N>` for DSD streams — return None for
|
||||
anything we can't render as a plain integer; the overlay just skips it."""
|
||||
if not audio_str:
|
||||
return None, None, None
|
||||
parts = audio_str.split(":")
|
||||
if len(parts) < 3:
|
||||
return None, None, None
|
||||
def _maybe_int(v):
|
||||
try: return int(v)
|
||||
except (TypeError, ValueError): return None
|
||||
return _maybe_int(parts[0]), _maybe_int(parts[1]), _maybe_int(parts[2])
|
||||
|
||||
|
||||
def _audio_info(status: dict, song: dict) -> dict:
|
||||
sr, bits, ch = _parse_audio(status.get("audio"))
|
||||
bitrate = None
|
||||
raw_br = status.get("bitrate")
|
||||
if raw_br is not None:
|
||||
try:
|
||||
bitrate = int(raw_br)
|
||||
except (TypeError, ValueError):
|
||||
bitrate = None
|
||||
# MPD reports 0 kbps for paused/stopped; surface as missing instead
|
||||
# of a misleading "0 kbps".
|
||||
if bitrate is not None and bitrate <= 0:
|
||||
bitrate = None
|
||||
return {
|
||||
"format": _detect_format(song.get("file")),
|
||||
"samplerate": sr,
|
||||
"bits": bits,
|
||||
"channels": ch,
|
||||
"bitrate": bitrate,
|
||||
}
|
||||
|
||||
|
||||
# Module-level cache: MPD stats barely move between ticks (only on file
|
||||
# add/remove), so we refresh every STATS_REFRESH_SEC and reuse otherwise.
|
||||
_stats_cache = {"data": None, "next_refresh": 0.0}
|
||||
@@ -246,6 +317,7 @@ def mpd_to_event(status: dict, song: dict, next_songs: list | None = None,
|
||||
"coverHash": cover_hash,
|
||||
"playback": playback,
|
||||
"stats": stats,
|
||||
"audio": _audio_info(status, song),
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +333,7 @@ class SharedState:
|
||||
"coverPath": None, "coverHash": None,
|
||||
"playback": {"volume": None, "repeat": False, "random": False, "single": False, "consume": False},
|
||||
"stats": None,
|
||||
"audio": {"format": None, "samplerate": None, "bits": None, "channels": None, "bitrate": None},
|
||||
}
|
||||
self.changed = asyncio.Event()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user