mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-12 22:28:06 +00:00
fix(vegas): carry the new keys through config, and correct two docs
Three findings from CodeRabbit, all valid. to_dict() and update() enumerate keys explicitly and had not learned the three new ones, so get_status() never reported them and a live config change never applied -- turning live_in_ticker on in the web UI would have done nothing until a restart. update() clamps the weights exactly as from_config does. The vegas_scroll key count in ADVANCED_FEATURES said 29; the template has 30. My arithmetic, not the reviewer's. The third was a documentation error rather than a code one, and I have fixed it the other way round. The docs claimed a raising get_vegas_priority_weight() is treated as weight 1. The code instead falls through to the core's own live-content check, and that is the better behaviour: the hook is only how a plugin asks for *more* than live_weight, and has_live_priority/has_live_content are separate methods guarded separately, so a plugin with a broken weight calculation should lose the favorite distinction and keep the live boost. Said so in the code, the base-plugin docstring and the API reference. The test fake now fails in each place independently, because the two failures mean different things: a broken hook still earns live_weight, a plugin that cannot say whether it is live has nothing to fall back on and weighs 1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ui/code/session_01Udr6MfaFLUPhX5Fgo67Jf5
This commit is contained in:
co-authored by
Claude Opus 5
parent
8c00df2e13
commit
611eef0597
@@ -64,7 +64,7 @@ JSON is optional.
|
||||
| `target_fps` | `125` | Target frame rate |
|
||||
| `buffer_ahead` | `2` | Number of plugins buffered ahead |
|
||||
|
||||
This table is a subset — `display.vegas_scroll` supports 29 keys in
|
||||
This table is a subset — `display.vegas_scroll` supports 30 keys in
|
||||
total. See the full list in
|
||||
[CONFIG_REFERENCE.md](CONFIG_REFERENCE.md#displayvegas_scroll--continuous-scroll-mode).
|
||||
|
||||
|
||||
@@ -201,8 +201,10 @@ def get_vegas_priority_weight(self):
|
||||
|
||||
The weight is per *plugin*, not per game: a scoreboard showing four live games
|
||||
still occupies one slot at a time and rotates its own games within it. Values
|
||||
are clamped to 1–10 by the caller, and an exception here is caught and
|
||||
treated as weight 1 rather than breaking the rotation.
|
||||
are clamped to 1–10 by the caller. An exception here is caught and logged, and
|
||||
the core then falls back to its own live-content check — so a plugin whose
|
||||
weight calculation is broken still gets `live_weight` for a game that really
|
||||
is live, rather than being demoted to 1.
|
||||
|
||||
Only consulted when the user has set `vegas_scroll.live_in_ticker`. With the
|
||||
default (`false`) live content preempts Vegas entirely and there is no ticker
|
||||
|
||||
@@ -587,6 +587,10 @@ class BasePlugin(ABC):
|
||||
within that slot; this controls how often the plugin itself comes
|
||||
round.
|
||||
|
||||
Raising is safe: the core logs it and falls back to its own
|
||||
live-content check, so a broken weight calculation costs the plugin
|
||||
the favorite distinction but not the live boost.
|
||||
|
||||
Returns:
|
||||
Slots per cycle (clamped to 1..10 by the caller), or None to
|
||||
defer to the core's own live-content weighting.
|
||||
|
||||
@@ -236,6 +236,9 @@ class VegasModeConfig:
|
||||
'lead_in_width': self.lead_in_width,
|
||||
'plugins_per_cycle': self.plugins_per_cycle,
|
||||
'max_plugin_width_ratio': self.max_plugin_width_ratio,
|
||||
'live_in_ticker': self.live_in_ticker,
|
||||
'live_weight': self.live_weight,
|
||||
'favorite_live_weight': self.favorite_live_weight,
|
||||
'overflow_mode': self.overflow_mode,
|
||||
'plugin_order': self.plugin_order,
|
||||
'excluded_plugins': list(self.excluded_plugins),
|
||||
@@ -403,6 +406,15 @@ class VegasModeConfig:
|
||||
|
||||
if 'enabled' in vegas_config:
|
||||
self.enabled = vegas_config['enabled']
|
||||
if 'live_in_ticker' in vegas_config:
|
||||
self.live_in_ticker = bool(vegas_config['live_in_ticker'])
|
||||
# Clamped exactly as from_config does: a weight below 1 would drop the
|
||||
# plugin from the rotation, and a huge one starves everything else.
|
||||
if 'live_weight' in vegas_config:
|
||||
self.live_weight = max(1, min(10, int(vegas_config['live_weight'])))
|
||||
if 'favorite_live_weight' in vegas_config:
|
||||
self.favorite_live_weight = max(
|
||||
1, min(10, int(vegas_config['favorite_live_weight'])))
|
||||
if 'scroll_speed' in vegas_config:
|
||||
self.scroll_speed = float(vegas_config['scroll_speed'])
|
||||
if 'separator_width' in vegas_config:
|
||||
|
||||
@@ -441,6 +441,11 @@ class StreamManager:
|
||||
if declared is not None:
|
||||
return max(1, min(10, int(declared)))
|
||||
except Exception:
|
||||
# Deliberately falls through to the core's own live check rather
|
||||
# than demoting to 1. The plugin's weight calculation is broken,
|
||||
# but has_live_priority() and has_live_content() are separate
|
||||
# methods guarded separately below -- a plugin that genuinely has
|
||||
# a live game should still get live_weight for it.
|
||||
logger.exception("[%s] get_vegas_priority_weight() failed", plugin_id)
|
||||
|
||||
try:
|
||||
|
||||
@@ -23,23 +23,33 @@ from src.vegas_mode.stream_manager import StreamManager
|
||||
|
||||
|
||||
class FakePlugin:
|
||||
def __init__(self, live=False, declared=None, raises=False):
|
||||
"""A plugin that can fail in each place independently.
|
||||
|
||||
hook_raises and live_raises are separate because they mean different
|
||||
things: a broken weight calculation should still leave the core's own
|
||||
live-content check usable, while a plugin that cannot answer whether it is
|
||||
live at all has nothing left to fall back on.
|
||||
"""
|
||||
|
||||
def __init__(self, live=False, declared=None, raises=False,
|
||||
hook_raises=False, live_raises=False):
|
||||
self._live = live
|
||||
self._declared = declared
|
||||
self._raises = raises
|
||||
self._hook_raises = hook_raises or raises
|
||||
self._live_raises = live_raises or raises
|
||||
self.enabled = True
|
||||
|
||||
def has_live_priority(self):
|
||||
if self._raises:
|
||||
raise RuntimeError("plugin blew up")
|
||||
if self._live_raises:
|
||||
raise RuntimeError("cannot say whether I am live")
|
||||
return self._live
|
||||
|
||||
def has_live_content(self):
|
||||
return self._live
|
||||
|
||||
def get_vegas_priority_weight(self):
|
||||
if self._raises:
|
||||
raise RuntimeError("plugin blew up")
|
||||
if self._hook_raises:
|
||||
raise RuntimeError("weight calculation blew up")
|
||||
return self._declared
|
||||
|
||||
|
||||
@@ -91,10 +101,29 @@ class TestWeightsComeFromTheRightPlace:
|
||||
assert sm._plugin_weight('a') == 10
|
||||
assert sm._plugin_weight('b') == 1
|
||||
|
||||
def test_a_plugin_that_raises_does_not_break_the_rotation(self):
|
||||
def test_a_plugin_that_raises_everywhere_weighs_one(self):
|
||||
sm = _manager({'bad': FakePlugin(raises=True)})
|
||||
assert sm._plugin_weight('bad') == 1
|
||||
|
||||
def test_a_broken_hook_still_earns_the_live_boost(self):
|
||||
# The hook is only how a plugin asks for *more* than live_weight.
|
||||
# Losing it should cost the favorite distinction, not the live boost:
|
||||
# has_live_priority/has_live_content are separate and still work.
|
||||
sm = _manager({'mlb': FakePlugin(live=True, hook_raises=True)},
|
||||
live_weight=4)
|
||||
assert sm._plugin_weight('mlb') == 4
|
||||
|
||||
def test_a_broken_hook_on_a_quiet_plugin_weighs_one(self):
|
||||
sm = _manager({'clock': FakePlugin(live=False, hook_raises=True)},
|
||||
live_weight=4)
|
||||
assert sm._plugin_weight('clock') == 1
|
||||
|
||||
def test_a_plugin_that_cannot_say_whether_it_is_live_weighs_one(self):
|
||||
# Nothing left to fall back on, so no boost.
|
||||
sm = _manager({'mlb': FakePlugin(live=True, live_raises=True)},
|
||||
live_weight=4)
|
||||
assert sm._plugin_weight('mlb') == 1
|
||||
|
||||
def test_an_unknown_plugin_weighs_one(self):
|
||||
assert _manager({})._plugin_weight('ghost') == 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user