Skip to content

Commit 6fdd882

Browse files
authored
Add audio overlay state to PlayerQueue (#295)
1 parent 01f6e3e commit 6fdd882

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

music_assistant_models/enums.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,6 @@ class ProviderFeature(StrEnum):
668668
AUDIO_SOURCE = "audio_source"
669669
# provider can enumerate sound effect items (live, not library-backed)
670670
SOUND_EFFECTS = "sound_effects"
671-
AUDIO_OVERLAY = "audio_overlay" # plugin can mix an audio overlay into queue playback
672671

673672
#
674673
# OTHER FEATURES (plugin-only)

music_assistant_models/player_queue.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ class PlayerQueue(DataClassDictMixin):
3636
repeat_mode: RepeatMode = RepeatMode.OFF
3737
crossfade_enabled: bool = False
3838
autoplay_enabled: bool = False
39+
# audio overlay: a looping sound effect mixed into this queue's playback.
40+
# overlay_source holds the selected sound effect (kept when the overlay is
41+
# disabled so it can be re-enabled with the same sound), overlay_volume is
42+
# the overlay loudness relative to the music in percent (100 = equally loud).
43+
overlay_enabled: bool = False
44+
overlay_source: ItemMapping | None = None
45+
overlay_volume: int = 100
3946
# smart_fades_active: whether the queue's effective crossfade is currently smart crossfade
4047
# (i.e. crossfade is on, smart is preferred, and smart fades are available). Derived at runtime
4148
# by the server, read-only and not persisted; lets clients show a smart-fades indicator.

tests/test_player_queue.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Tests for the PlayerQueue model (deprecated-key back-compat serialization)."""
22

3+
from music_assistant_models.enums import MediaType
4+
from music_assistant_models.media_items import ItemMapping
35
from music_assistant_models.player_queue import PlayerQueue
46

57

@@ -26,3 +28,41 @@ def test_autoplay_dont_stop_backcompat_preserved() -> None:
2628
"""The existing autoplay <-> dont_stop_the_music back-compat still holds."""
2729
d = _queue().to_dict()
2830
assert d["dont_stop_the_music_enabled"] == d["autoplay_enabled"]
31+
32+
33+
def test_overlay_defaults() -> None:
34+
"""The audio overlay fields have sane defaults."""
35+
queue = _queue()
36+
assert queue.overlay_enabled is False
37+
assert queue.overlay_source is None
38+
assert queue.overlay_volume == 100
39+
40+
41+
def test_overlay_serialize_roundtrip() -> None:
42+
"""A populated audio overlay survives a to_dict -> from_dict round-trip."""
43+
queue = _queue()
44+
queue.overlay_enabled = True
45+
queue.overlay_source = ItemMapping(
46+
media_type=MediaType.SOUND_EFFECT,
47+
item_id="rain-loop",
48+
provider="soundlib",
49+
name="Rain Loop",
50+
)
51+
queue.overlay_volume = 40
52+
restored = PlayerQueue.from_dict(queue.to_dict())
53+
assert restored.overlay_enabled is True
54+
assert restored.overlay_source is not None
55+
assert restored.overlay_source.media_type == MediaType.SOUND_EFFECT
56+
assert restored.overlay_source.item_id == "rain-loop"
57+
assert restored.overlay_volume == 40
58+
59+
60+
def test_payload_without_overlay_keys_deserializes() -> None:
61+
"""Payloads from older servers without the overlay keys still deserialize."""
62+
legacy = _queue().to_dict()
63+
for key in ("overlay_enabled", "overlay_source", "overlay_volume"):
64+
legacy.pop(key, None)
65+
restored = PlayerQueue.from_dict(legacy)
66+
assert restored.overlay_enabled is False
67+
assert restored.overlay_source is None
68+
assert restored.overlay_volume == 100

0 commit comments

Comments
 (0)