Skip to content

fix(stock-news): scroll speed/FPS, sparse ticker on startup, publisher/age styling, price coloring#174

Merged
ChuckBuilds merged 2 commits into
mainfrom
fix/stock-news-ticker-speed-and-styling
Jul 10, 2026
Merged

fix(stock-news): scroll speed/FPS, sparse ticker on startup, publisher/age styling, price coloring#174
ChuckBuilds merged 2 commits into
mainfrom
fix/stock-news-ticker-speed-and-styling

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Choppy/slow scrolling (root cause): stock-news never set self.enable_scrolling = True, so the core display loop ran it through the 1 FPS "normal" path instead of the 125 FPS high-FPS path used by sibling ticker plugins (ledmatrix-stocks, leaderboard). Combined with the frame-based scroll math (tuned for ~100 FPS), this made the ticker crawl at a fraction of its configured speed in visible chunky jumps. Fixed by setting enable_scrolling = True in __init__.
  • Slow default speed: scroll_pixels_per_second defaulted to 25 — 2-4x slower than odds-ticker (50) and news/ledmatrix-stocks (~100 effective) — and was never retuned when frame-based scrolling was added in 2.3.4. Bumped default to 60.
  • Sparse ticker after restart/config change: a fresh start only fetches one symbol per update() call, spread across update_interval_seconds / n (300s apart for 3 symbols) — plus the plugin never declared a manifest-level update_interval, so the core only called update() every 60s (its fallback default). Together this could leave the ticker at 1-2 headlines for up to ~15 minutes. Added eager_fetch_on_startup (default on, fetches every never-seen symbol at plain update() cadence until each has data) and declared "update_interval": 30 in the manifest.
  • Publisher/age styling: previously one combined suffix segment sharing publisher_color and the main headline font. Now independent segments, each with its own font_size/font_path/color (publisher_font_size, publisher_font_path, age_font_size, age_font_path, age_color).
  • Price coloring: new price_color_mode (fixed default / change) optionally colors the price green/red (price_up_color/price_down_color) by movement since market open, using Yahoo's regularMarketChange.

Version bumped 2.4.1 → 2.4.4, plugins.json synced via pre-commit hook.

Test plan

  • python -m py_compile manager.py and JSON-validated both schema/manifest
  • scripts/check_plugin.py --plugin stock-news — PASS on all 7 panel sizes (64x32, 128x32, 64x64, 128x64, 256x32, 128x96, 256x128)
  • Deployed to a live devpi test rig: confirmed FPS check ... needs_high_fps: True and ~60 FPS scroll (was ~1 FPS)
  • Confirmed ticker fills to 3/3 configured symbols within ~60s of a restart (was ~15 min)
  • No render errors in logs with the new publisher/age/price rendering path
  • Manual visual check of publisher/age independent styling and price up/down coloring (needs show_price + price_color_mode: change enabled with live market data)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added more display customization options for stock news, including separate styling for publisher and age text.
    • Introduced an optional price color mode that can switch between fixed colors and movement-based up/down colors.
    • Added an option to fetch updates immediately on startup for faster initial content loading.
  • Bug Fixes

    • Improved font loading and update behavior for more consistent display across configurations.
  • Chores

    • Bumped the plugin to version 2.4.4 and refreshed release metadata.

…ent publisher/age styling, price change coloring (v2.4.4)

- Raise default scroll_pixels_per_second 25 -> 60: it was 2-4x slower than
  sibling ticker plugins (odds-ticker: 50, news/ledmatrix-stocks: ~100
  effective) and was never retuned after frame-based scrolling landed in 2.3.4.
- Set self.enable_scrolling = True so the core display loop uses its 125 FPS
  high-FPS path instead of the 1 FPS default path. Without this flag the
  ticker's frame-based scroll math (tuned for ~100 FPS) only got ~1 real
  frame/second, making it scroll at a fraction of the configured speed in
  visibly choppy jumps regardless of scroll_pixels_per_second.
- Add eager_fetch_on_startup (default on): fetch every never-seen symbol at
  update() cadence instead of waiting for the steady-state per-symbol
  spacing (update_interval_seconds / symbol count), so a fresh restart or
  config change doesn't leave the ticker showing 1-2 headlines for minutes.
- Add manifest update_interval=30 (previously undeclared, silently defaulted
  to the core's 60s fallback) so the above cadence is itself 2x faster.
- Publisher and age are now independent segments (own font_size/font_path/
  color each: publisher_font_size, publisher_font_path, age_font_size,
  age_font_path, age_color) instead of one combined suffix string that
  always used publisher_color and the main headline font.
- Add price_color_mode ('fixed' default / 'change'): optionally color the
  price green/red (price_up_color/price_down_color) by movement since
  market open via Yahoo's regularMarketChange, instead of always text_color.

Verified on devpi: FPS check now reports needs_high_fps=True and the scroll
runs at ~60 FPS (was ~1 FPS); ticker fills to 3/3 configured symbols within
~60s of a restart (was ~15 min); plugin safety harness passes at all 7 panel
sizes with no render errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ChuckBuilds, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 19e59764-2e5a-4d3f-9cb0-7233b48595a4

📥 Commits

Reviewing files that changed from the base of the PR and between 9ba0311 and 99dff81.

📒 Files selected for processing (1)
  • plugins/stock-news/manifest.json
📝 Walkthrough

Walkthrough

The stock-news plugin is updated to version 2.4.4, adding independent publisher/age font and color settings, a price color mode (fixed vs. change-based), an eager fetch on startup option, forced scrolling rendering, and updated scroll speed defaults. Manifest and plugin registry metadata are updated accordingly.

Changes

Stock News Plugin Enhancements

Layer / File(s) Summary
Config schema additions
plugins/stock-news/config_schema.json
Adds price_color_mode, publisher/age font size and path fields, eager_fetch_on_startup, changes default scroll_pixels_per_second to 60.0, and adds age_color/price_up_color/price_down_color to feed colors.
Config parsing and scrolling init
plugins/stock-news/manager.py
Forces enable_scrolling = True on init and parses the new eager-fetch, font, and color config fields.
Font loading and registration
plugins/stock-news/manager.py
Adds reusable _load_font() helper with fallback and loads/registers separate publisher and age fonts alongside headline/symbol fonts.
Eager fetch scheduling and price data
plugins/stock-news/manager.py
Adds an eager-fill fetch path for never-seen symbols and extracts/caches price_change from Yahoo Finance data.
Rendering: independent publisher/age segments and price coloring
plugins/stock-news/manager.py
Reworks rendering to draw publisher and age as separate bullet-prefixed segments with distinct fonts/colors, and colors $price based on price_color_mode and price_change.
Hot-reload detection and info exposure
plugins/stock-news/manager.py
Updates on_config_change() to detect new font setting changes and expands get_info() with new font, color, price mode, and eager-fetch fields.
Manifest and registry version bump
plugins/stock-news/manifest.json, plugins.json
Bumps version to 2.4.4, sets update_interval: 30, adds changelog entries, updates last_updated, and syncs the plugin registry entry.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main changes: faster scrolling, startup fetch improvements, styling splits, and price coloring.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stock-news-ticker-speed-and-styling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 24 complexity

Metric Results
Complexity 24

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/stock-news/manifest.json`:
- Around line 4-9: The top release entry in the StockNewsTickerPlugin manifest
is using a PATCH version for new backward-compatible config options, but it
should be a MINOR bump instead. Update the version for this release to 2.5.0 and
keep it consistent across the manifest’s version field, the corresponding entry
in the versions history array, and the plugins.json latest_version reference.
Use the existing StockNewsTickerPlugin manifest/version entries as the anchor
points when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0e434fd-94ca-4978-bccd-1f12709136ed

📥 Commits

Reviewing files that changed from the base of the PR and between 4e5de3c and 9ba0311.

📒 Files selected for processing (4)
  • plugins.json
  • plugins/stock-news/config_schema.json
  • plugins/stock-news/manager.py
  • plugins/stock-news/manifest.json

Comment thread plugins/stock-news/manifest.json
…ield

The safety CI validates manifest.json against core/schema/manifest_schema.json,
which types `dependencies` as a flat array of pip package name strings (legacy
field, superseded by requirements.txt). The `{"managers": ["cache_manager"]}`
shape fails that check and isn't read by any core code path (grepped
plugin_manager.py/store_manager.py) — cache_manager is a built-in core manager
every plugin already gets, not a pip dependency to install. Sibling plugins
without real pip deps (ledmatrix-stocks, ledmatrix-weather, news) omit this
field entirely, so drop it here too rather than reshaping it into a
technically-valid-but-misleading pip dependency list.
@ChuckBuilds ChuckBuilds merged commit 539a007 into main Jul 10, 2026
3 checks passed
@ChuckBuilds ChuckBuilds deleted the fix/stock-news-ticker-speed-and-styling branch July 10, 2026 16:45
ChuckBuilds pushed a commit that referenced this pull request Jul 10, 2026
Follows the maintainer's correction on #175: the core's manifest
validator flags `ledmatrix_min` as deprecated and expects
`ledmatrix_min_version`. Switch the music versions[] entries (1.0.8,
1.0.7, 1.0.6) to `ledmatrix_min_version` so device installs don't log a
deprecated-field warning. Also merges the latest main (#174, #175) and
regenerates plugins.json.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB
ChuckBuilds pushed a commit that referenced this pull request Jul 10, 2026
Follows the maintainer's correction on #175: the core's manifest
validator flags `ledmatrix_min` as deprecated and expects
`ledmatrix_min_version`. Normalize every versions[] entry in the flights
and stocks manifests to `ledmatrix_min_version` so device installs don't
log deprecated-field warnings. (Latest main, incl. #174/#175, was merged
in the preceding commit.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB
ChuckBuilds added a commit that referenced this pull request Jul 10, 2026
* chore(license): standardize flights, music, stocks to GPL-3.0

Completes the repo-wide MIT -> GPL-3.0 pass for the plugins not covered by
the other audit PRs. All first-party:

- ledmatrix-flights (1.10.0 -> 1.10.1): manifest "license" + README MIT ->
  GPL-3.0 (its LICENSE file was already GPL).
- ledmatrix-music (1.0.6 -> 1.0.7): LICENSE file + manifest "license" +
  README MIT -> GPL-3.0.
- ledmatrix-stocks (2.3.0 -> 2.3.1): manifest "license" MIT -> GPL-3.0 (its
  LICENSE file was already GPL).

No code changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* fix(ledmatrix-stocks): guard process_deferred_updates for harness compatibility

The plugin-safety harness renders each changed plugin, and its
BoundsCheckingDisplayManager does not implement process_deferred_updates(),
so stocks crashed at every size once the license bump made it a "changed"
plugin. Guard the call with hasattr — production DisplayManager still runs it;
harness/other managers that lack it are skipped. No production behavior change.

Note: leaderboard, odds-ticker, news, and stock-news call the same method and
would hit this too when next touched — the core harness double is missing it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* chore: defer ledmatrix-music relicense (pre-existing 64px overflow)

Relicensing made music a "changed" plugin, so the safety harness rendered it
and caught a PRE-EXISTING overflow on the 64px-wide panels
([FAIL] 64x32 / 64x64 now_playing overflow bbox=(64,...)) — album-art + text
don't fit a 64px width. That's a narrow-panel layout bug, not a licensing
issue, and needs a real rendering fix (best verified against the core
harness). Revert music to its current state so this PR (flights + stocks ->
GPL-3.0) can land; music's relicense will follow once the overflow is fixed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* Use non-deprecated ledmatrix_min_version in flights + stocks manifests

Follows the maintainer's correction on #175: the core's manifest
validator flags `ledmatrix_min` as deprecated and expects
`ledmatrix_min_version`. Normalize every versions[] entry in the flights
and stocks manifests to `ledmatrix_min_version` so device installs don't
log deprecated-field warnings. (Latest main, incl. #174/#175, was merged
in the preceding commit.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

---------

Co-authored-by: Claude <noreply@anthropic.com>
ChuckBuilds added a commit that referenced this pull request Jul 10, 2026
CI's version-bump enforcement failed because this PR's code changes to
display_renderer.py and manager.py weren't matched by manifest version
bumps. Branch was 5 commits behind main (missing #177's GPL/hasattr-guard
work, which had already taken ledmatrix-stocks to 2.3.1) — merged main
in first so this bumps from the real current version instead of colliding
with an already-published one.

- ledmatrix-stocks: 2.3.1 -> 2.3.2 (logo_x/logo_gap spacing fix)
- odds-ticker: 1.1.4 -> 1.1.5 (baseball odds-column sizing fix), and
  dropped its dependencies.managers object — same schema shape as the
  bug fixed in stock-news (PR #174): manifest_schema.json types
  `dependencies` as a flat array of pip package names, and nothing in
  core reads a `managers` key. It was never touched before because CI
  only validates changed plugins, but editing this manifest for the
  version bump means the schema check now runs against it for real.

New versions[] entries use ledmatrix_min_version (not the deprecated
ledmatrix_min flagged by core's store_manager.py validator).

plugins.json synced via update_registry.py.
ChuckBuilds added a commit that referenced this pull request Jul 10, 2026
* Fix odds-ticker baseball gap and stock-ticker logo spacing

odds-ticker: for live baseball games, odds_width was sized from the
away/home odds text ("Bases: 1B2B3B", "Count: 3-2" - up to 104px at
8px font) even though that text is never drawn; a 24px bases-diamond
graphic is drawn instead, left-aligned in that column. The next
column (inning info) started after the full odds_width, leaving up
to ~80px of dead space between the bases graphic and the inning
text. Detect the live-baseball case before sizing the column and use
the actual 24px graphic width instead of maxing against the unused
placeholder text.

ledmatrix-stocks: logo_x (2px) and logo_gap (4px, between the logo's
right edge and the symbol/price text) were too tight for a ~26px-tall
logo on a 32px-tall display. Bumped to 4px and 8px.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(plugins): bump versions for ledmatrix-stocks and odds-ticker

CI's version-bump enforcement failed because this PR's code changes to
display_renderer.py and manager.py weren't matched by manifest version
bumps. Branch was 5 commits behind main (missing #177's GPL/hasattr-guard
work, which had already taken ledmatrix-stocks to 2.3.1) — merged main
in first so this bumps from the real current version instead of colliding
with an already-published one.

- ledmatrix-stocks: 2.3.1 -> 2.3.2 (logo_x/logo_gap spacing fix)
- odds-ticker: 1.1.4 -> 1.1.5 (baseball odds-column sizing fix), and
  dropped its dependencies.managers object — same schema shape as the
  bug fixed in stock-news (PR #174): manifest_schema.json types
  `dependencies` as a flat array of pip package names, and nothing in
  core reads a `managers` key. It was never touched before because CI
  only validates changed plugins, but editing this manifest for the
  version bump means the schema check now runs against it for real.

New versions[] entries use ledmatrix_min_version (not the deprecated
ledmatrix_min flagged by core's store_manager.py validator).

plugins.json synced via update_registry.py.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
ChuckBuilds added a commit that referenced this pull request Jul 10, 2026
…wing (+ GPL-3.0) (#179)

* fix(ledmatrix-music): clip scrolling text to viewport (fix 64px overflow) + GPL-3.0

The now-playing title/artist/album marquee drew the full (rotated) string at
the text-area x with no right-edge clip, so long text ran past the panel's
right edge. The safety harness flagged this as an overflow on the 64px-wide
panels (64x32 / 64x64), where the text area is only ~29px wide.

Add _clip_text_to_width() and apply it to all four text draws so the marquee
stays inside its viewport: long text still scrolls (the char-based rotation is
unchanged) — it's just clipped on the right instead of overflowing the panel.

Also relicense to GPL-3.0 (LICENSE + manifest + README). music was the plugin
deferred from the repo-wide MIT -> GPL-3.0 pass because of this overflow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* fix(ledmatrix-music): draw no text when the panel has no text room (square panels)

Follow-up to the viewport clip: on square panels (e.g. 64x64) the album art
is sized to the panel height, so it fills the full width and text_area_width
goes negative. The clip helper's `max_width <= 0` guard returned the text
UNCLIPPED, so it was still drawn off-panel (overflow bbox=(64,28,91,36) at
64x64). Now return an empty string when there's no room, and skip the progress
bar too. Album art fills the panel; no text is drawn rather than overflowing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* fix(ledmatrix-music): clip the "Nothing Playing" screen to the panel width

That was the real overflow the harness caught (CI has no auth -> no track ->
the "Nothing Playing" idle screen renders). The text is centered via
x = (width - text_width)//2, which goes negative when the text is wider than
the panel (64px), spilling off both edges — matching the failing bbox exactly
(y = height//2 - 4 = 12 at 64x32, 28 at 64x64). Clip the text to the panel
width and clamp x to >= 0. (The earlier marquee viewport clip is still correct
for the now-playing view with a real track.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* fix(ledmatrix-music): keep the ellipsis when truncating non-scrolling text

When scrolling is disabled, the title/artist/album were truncated with a
rough char-count estimate (`text[:width//6] + "..."`) and then passed
through the draw-time viewport clip, which could trim the trailing "..."
back off — leaving no truncation indicator. Add
`_truncate_text_with_ellipsis`, which reserves room for the ellipsis
before clipping so the "..." always survives and the result fits the
text-area viewport.

Bumps ledmatrix-music to 1.0.8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

* Merge main + use non-deprecated ledmatrix_min_version in music manifest

Follows the maintainer's correction on #175: the core's manifest
validator flags `ledmatrix_min` as deprecated and expects
`ledmatrix_min_version`. Switch the music versions[] entries (1.0.8,
1.0.7, 1.0.6) to `ledmatrix_min_version` so device installs don't log a
deprecated-field warning. Also merges the latest main (#174, #175) and
regenerates plugins.json.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant