Rename radio media params and add widget emit effects
This commit is contained in:
@@ -75,8 +75,9 @@ ITEM_DEFINITIONS: dict[ItemType, ItemDefinition] = {
|
||||
}
|
||||
|
||||
ITEM_PROPERTY_OPTIONS: dict[str, tuple[str, ...]] = {
|
||||
"effect": RADIO_EFFECT_OPTIONS,
|
||||
"channel": RADIO_CHANNEL_OPTIONS,
|
||||
"mediaEffect": RADIO_EFFECT_OPTIONS,
|
||||
"emitEffect": RADIO_EFFECT_OPTIONS,
|
||||
"mediaChannel": RADIO_CHANNEL_OPTIONS,
|
||||
"timeZone": CLOCK_TIME_ZONE_OPTIONS,
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ EDITABLE_PROPERTIES: tuple[str, ...] = (
|
||||
"title",
|
||||
"streamUrl",
|
||||
"enabled",
|
||||
"channel",
|
||||
"mediaVolume",
|
||||
"effect",
|
||||
"effectValue",
|
||||
"mediaChannel",
|
||||
"mediaEffect",
|
||||
"mediaEffectValue",
|
||||
"facing",
|
||||
"emitRange",
|
||||
)
|
||||
@@ -31,10 +31,10 @@ DEFAULT_TITLE = "radio"
|
||||
DEFAULT_PARAMS: dict = {
|
||||
"streamUrl": "",
|
||||
"enabled": True,
|
||||
"channel": "stereo",
|
||||
"mediaVolume": 50,
|
||||
"effect": "off",
|
||||
"effectValue": 50,
|
||||
"mediaChannel": "stereo",
|
||||
"mediaEffect": "off",
|
||||
"mediaEffectValue": 50,
|
||||
"facing": 0,
|
||||
"emitRange": 20,
|
||||
}
|
||||
@@ -46,14 +46,14 @@ PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
||||
"streamUrl": {"valueType": "text", "tooltip": "Audio stream URL used by this radio."},
|
||||
"enabled": {"valueType": "boolean", "tooltip": "Turns playback on or off for this radio."},
|
||||
"channel": {"valueType": "list", "tooltip": "Select how the station audio channels are rendered."},
|
||||
"mediaVolume": {
|
||||
"valueType": "number",
|
||||
"tooltip": "Playback media volume percent for this radio.",
|
||||
"range": {"min": 0, "max": 100, "step": 1},
|
||||
},
|
||||
"effect": {"valueType": "list", "tooltip": "Select the active radio effect."},
|
||||
"effectValue": {
|
||||
"mediaChannel": {"valueType": "list", "tooltip": "Select how the station audio channels are rendered."},
|
||||
"mediaEffect": {"valueType": "list", "tooltip": "Select the active radio effect."},
|
||||
"mediaEffectValue": {
|
||||
"valueType": "number",
|
||||
"tooltip": "Amount for the selected effect.",
|
||||
"range": {"min": 0, "max": 100, "step": 0.1},
|
||||
@@ -107,23 +107,23 @@ def validate_update(item: WorldItem, next_params: dict) -> dict:
|
||||
raise ValueError("mediaVolume must be between 0 and 100.")
|
||||
next_params["mediaVolume"] = media_volume
|
||||
|
||||
effect = str(next_params.get("effect", "off")).strip().lower()
|
||||
effect = str(next_params.get("mediaEffect", "off")).strip().lower()
|
||||
if effect not in EFFECT_OPTIONS:
|
||||
raise ValueError("effect must be one of reverb, echo, flanger, high_pass, low_pass, off.")
|
||||
next_params["effect"] = effect
|
||||
raise ValueError("mediaEffect must be one of reverb, echo, flanger, high_pass, low_pass, off.")
|
||||
next_params["mediaEffect"] = effect
|
||||
|
||||
channel = str(next_params.get("channel", "stereo")).strip().lower()
|
||||
channel = str(next_params.get("mediaChannel", "stereo")).strip().lower()
|
||||
if channel not in CHANNEL_OPTIONS:
|
||||
raise ValueError("channel must be one of stereo, mono, left, right.")
|
||||
next_params["channel"] = channel
|
||||
raise ValueError("mediaChannel must be one of stereo, mono, left, right.")
|
||||
next_params["mediaChannel"] = channel
|
||||
|
||||
try:
|
||||
effect_value = float(next_params.get("effectValue", 50))
|
||||
effect_value = float(next_params.get("mediaEffectValue", 50))
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError("effectValue must be a number.") from exc
|
||||
raise ValueError("mediaEffectValue must be a number.") from exc
|
||||
if not (0 <= effect_value <= 100):
|
||||
raise ValueError("effectValue must be between 0 and 100.")
|
||||
next_params["effectValue"] = round(effect_value, 1)
|
||||
raise ValueError("mediaEffectValue must be between 0 and 100.")
|
||||
next_params["mediaEffectValue"] = round(effect_value, 1)
|
||||
|
||||
try:
|
||||
facing = float(next_params.get("facing", item.params.get("facing", 0)))
|
||||
|
||||
@@ -17,6 +17,8 @@ EDITABLE_PROPERTIES: tuple[str, ...] = (
|
||||
"facing",
|
||||
"emitRange",
|
||||
"emitVolume",
|
||||
"emitEffect",
|
||||
"emitEffectValue",
|
||||
"useSound",
|
||||
"emitSound",
|
||||
)
|
||||
@@ -33,9 +35,12 @@ DEFAULT_PARAMS: dict = {
|
||||
"facing": 0,
|
||||
"emitRange": 15,
|
||||
"emitVolume": 100,
|
||||
"emitEffect": "off",
|
||||
"emitEffectValue": 50,
|
||||
"useSound": "",
|
||||
"emitSound": "",
|
||||
}
|
||||
EFFECT_OPTIONS: tuple[str, ...] = ("reverb", "echo", "flanger", "high_pass", "low_pass", "off")
|
||||
|
||||
PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."},
|
||||
@@ -56,6 +61,12 @@ PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
||||
"tooltip": "Emitted sound volume percent.",
|
||||
"range": {"min": 0, "max": 100, "step": 1},
|
||||
},
|
||||
"emitEffect": {"valueType": "list", "tooltip": "Effect applied to emitted sound."},
|
||||
"emitEffectValue": {
|
||||
"valueType": "number",
|
||||
"tooltip": "Amount for emit effect.",
|
||||
"range": {"min": 0, "max": 100, "step": 0.1},
|
||||
},
|
||||
"useSound": {"valueType": "sound", "tooltip": "Sound played on use. Filename assumes sounds folder, or use full URL."},
|
||||
"emitSound": {"valueType": "sound", "tooltip": "Looping emitted sound. Filename assumes sounds folder, or use full URL."},
|
||||
}
|
||||
@@ -113,6 +124,19 @@ def validate_update(item: WorldItem, next_params: dict) -> dict:
|
||||
raise ValueError("emitVolume must be between 0 and 100.")
|
||||
next_params["emitVolume"] = emit_volume
|
||||
|
||||
emit_effect = str(next_params.get("emitEffect", item.params.get("emitEffect", "off"))).strip().lower()
|
||||
if emit_effect not in EFFECT_OPTIONS:
|
||||
raise ValueError("emitEffect must be one of reverb, echo, flanger, high_pass, low_pass, off.")
|
||||
next_params["emitEffect"] = emit_effect
|
||||
|
||||
try:
|
||||
emit_effect_value = float(next_params.get("emitEffectValue", item.params.get("emitEffectValue", 50)))
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError("emitEffectValue must be a number.") from exc
|
||||
if not (0 <= emit_effect_value <= 100):
|
||||
raise ValueError("emitEffectValue must be between 0 and 100.")
|
||||
next_params["emitEffectValue"] = round(emit_effect_value, 1)
|
||||
|
||||
next_params["useSound"] = _normalize_sound_value(next_params.get("useSound", item.params.get("useSound", "")))
|
||||
next_params["emitSound"] = _normalize_sound_value(next_params.get("emitSound", item.params.get("emitSound", "")))
|
||||
return next_params
|
||||
|
||||
@@ -85,7 +85,7 @@ async def test_radio_use_toggles_enabled(monkeypatch: pytest.MonkeyPatch) -> Non
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_radio_channel_update_validates(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
async def test_radio_media_fields_update_validate(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
server = SignalingServer("127.0.0.1", 8765, None, None)
|
||||
ws = _fake_ws()
|
||||
client = ClientConnection(websocket=ws, id="u1", nickname="tester", x=5, y=6)
|
||||
@@ -106,17 +106,17 @@ async def test_radio_channel_update_validates(monkeypatch: pytest.MonkeyPatch) -
|
||||
|
||||
await server._handle_message(
|
||||
client,
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"channel": "left"}}),
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"mediaChannel": "left"}}),
|
||||
)
|
||||
assert send_payloads[-1].ok is True
|
||||
assert item.params.get("channel") == "left"
|
||||
assert item.params.get("mediaChannel") == "left"
|
||||
|
||||
await server._handle_message(
|
||||
client,
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"channel": "invalid"}}),
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"mediaChannel": "invalid"}}),
|
||||
)
|
||||
assert send_payloads[-1].ok is False
|
||||
assert "channel must be one of" in send_payloads[-1].message.lower()
|
||||
assert "mediachannel must be one of" in send_payloads[-1].message.lower()
|
||||
|
||||
await server._handle_message(
|
||||
client,
|
||||
@@ -139,6 +139,13 @@ async def test_radio_channel_update_validates(monkeypatch: pytest.MonkeyPatch) -
|
||||
assert send_payloads[-1].ok is True
|
||||
assert item.params.get("mediaVolume") == 12
|
||||
|
||||
await server._handle_message(
|
||||
client,
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"mediaEffect": "echo"}}),
|
||||
)
|
||||
assert send_payloads[-1].ok is True
|
||||
assert item.params.get("mediaEffect") == "echo"
|
||||
|
||||
await server._handle_message(
|
||||
client,
|
||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"emitRange": 12}}),
|
||||
@@ -285,6 +292,8 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"facing": 123.4,
|
||||
"emitRange": 7,
|
||||
"emitVolume": 42,
|
||||
"emitEffect": "reverb",
|
||||
"emitEffectValue": 63.2,
|
||||
"useSound": "ping.ogg",
|
||||
"emitSound": "https://example.com/ambient.ogg",
|
||||
},
|
||||
@@ -296,6 +305,8 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
assert item.params.get("facing") == 123.4
|
||||
assert item.params.get("emitRange") == 7
|
||||
assert item.params.get("emitVolume") == 42
|
||||
assert item.params.get("emitEffect") == "reverb"
|
||||
assert item.params.get("emitEffectValue") == 63.2
|
||||
assert item.params.get("useSound") == "sounds/ping.ogg"
|
||||
assert item.params.get("emitSound") == "https://example.com/ambient.ogg"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user