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 |
|
| `target_fps` | `125` | Target frame rate |
|
||||||
| `buffer_ahead` | `2` | Number of plugins buffered ahead |
|
| `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
|
total. See the full list in
|
||||||
[CONFIG_REFERENCE.md](CONFIG_REFERENCE.md#displayvegas_scroll--continuous-scroll-mode).
|
[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
|
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
|
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
|
are clamped to 1–10 by the caller. An exception here is caught and logged, and
|
||||||
treated as weight 1 rather than breaking the rotation.
|
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
|
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
|
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
|
within that slot; this controls how often the plugin itself comes
|
||||||
round.
|
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:
|
Returns:
|
||||||
Slots per cycle (clamped to 1..10 by the caller), or None to
|
Slots per cycle (clamped to 1..10 by the caller), or None to
|
||||||
defer to the core's own live-content weighting.
|
defer to the core's own live-content weighting.
|
||||||
|
|||||||
@@ -236,6 +236,9 @@ class VegasModeConfig:
|
|||||||
'lead_in_width': self.lead_in_width,
|
'lead_in_width': self.lead_in_width,
|
||||||
'plugins_per_cycle': self.plugins_per_cycle,
|
'plugins_per_cycle': self.plugins_per_cycle,
|
||||||
'max_plugin_width_ratio': self.max_plugin_width_ratio,
|
'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,
|
'overflow_mode': self.overflow_mode,
|
||||||
'plugin_order': self.plugin_order,
|
'plugin_order': self.plugin_order,
|
||||||
'excluded_plugins': list(self.excluded_plugins),
|
'excluded_plugins': list(self.excluded_plugins),
|
||||||
@@ -403,6 +406,15 @@ class VegasModeConfig:
|
|||||||
|
|
||||||
if 'enabled' in vegas_config:
|
if 'enabled' in vegas_config:
|
||||||
self.enabled = vegas_config['enabled']
|
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:
|
if 'scroll_speed' in vegas_config:
|
||||||
self.scroll_speed = float(vegas_config['scroll_speed'])
|
self.scroll_speed = float(vegas_config['scroll_speed'])
|
||||||
if 'separator_width' in vegas_config:
|
if 'separator_width' in vegas_config:
|
||||||
|
|||||||
@@ -441,6 +441,11 @@ class StreamManager:
|
|||||||
if declared is not None:
|
if declared is not None:
|
||||||
return max(1, min(10, int(declared)))
|
return max(1, min(10, int(declared)))
|
||||||
except Exception:
|
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)
|
logger.exception("[%s] get_vegas_priority_weight() failed", plugin_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -23,23 +23,33 @@ from src.vegas_mode.stream_manager import StreamManager
|
|||||||
|
|
||||||
|
|
||||||
class FakePlugin:
|
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._live = live
|
||||||
self._declared = declared
|
self._declared = declared
|
||||||
self._raises = raises
|
self._hook_raises = hook_raises or raises
|
||||||
|
self._live_raises = live_raises or raises
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
|
|
||||||
def has_live_priority(self):
|
def has_live_priority(self):
|
||||||
if self._raises:
|
if self._live_raises:
|
||||||
raise RuntimeError("plugin blew up")
|
raise RuntimeError("cannot say whether I am live")
|
||||||
return self._live
|
return self._live
|
||||||
|
|
||||||
def has_live_content(self):
|
def has_live_content(self):
|
||||||
return self._live
|
return self._live
|
||||||
|
|
||||||
def get_vegas_priority_weight(self):
|
def get_vegas_priority_weight(self):
|
||||||
if self._raises:
|
if self._hook_raises:
|
||||||
raise RuntimeError("plugin blew up")
|
raise RuntimeError("weight calculation blew up")
|
||||||
return self._declared
|
return self._declared
|
||||||
|
|
||||||
|
|
||||||
@@ -91,10 +101,29 @@ class TestWeightsComeFromTheRightPlace:
|
|||||||
assert sm._plugin_weight('a') == 10
|
assert sm._plugin_weight('a') == 10
|
||||||
assert sm._plugin_weight('b') == 1
|
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)})
|
sm = _manager({'bad': FakePlugin(raises=True)})
|
||||||
assert sm._plugin_weight('bad') == 1
|
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):
|
def test_an_unknown_plugin_weighs_one(self):
|
||||||
assert _manager({})._plugin_weight('ghost') == 1
|
assert _manager({})._plugin_weight('ghost') == 1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user