Skip to content

Feature: Up Next widget for Sonarr, Radarr and Lidarr - #554

Merged
SandObserver merged 4 commits into
mainfrom
feat/up-next-widget
Oct 25, 2026
Merged

SandObserver merged 4 commits into
mainfrom
feat/up-next-widget

Conversation

@SandObserver

@SandObserver SandObserver commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Add the upnext widget (small, medium, large): the next episodes, films and albums from up to six Sonarr, Radarr and Lidarr apps, soonest first. Each row has a day and time column, a kind bar and the title over its detail line. Small and medium show 3 rows, large 7; medium and large add the episode name.
  • Read /api/v3/calendar (Sonarr, Radarr) and /api/v1/calendar?includeArtist=true (Lidarr) with X-Api-Key, 14 days ahead, then 90 days when fewer than 8 items come back. A failed longer read keeps the shorter one and its 14 days.
  • Sonarr: read the calendar without includeSeries and fetch /api/v3/series/{id} only for the series that can reach the list, cached per server for 6 hours, bounded to 500 entries of strings capped at 300 characters and validated runtime and series type.
  • Parse replies in upnext-items.js with no I/O: daily shows drop the season and date-like names, runtimes past 24 hours fall back, rows past the Date range are skipped, consecutive episodes at one time merge into a range, premieres and finales are marked, Radarr gives one row per chosen release type, items listed by two apps show once.
  • Date-only films and albums stay on the server until their day ends at UTC-12; the browser drops them at local midnight and sorts every row in local time.
  • One failing app leaves the others on screen with a caption naming the app, also over the empty state; apps failing differently get a neutral line and each app's problem in spoken text. A Timed out error is a timeout. The widget fails only when every app fails. Empty state names the window and opens the app's calendar.
  • The minute refresh redraws rows only when their content changes and returns focus to the same row.
  • Rows link to /series/{slug}, /movie/{slug} and /album/{id} through serviceLink; each row carries its spoken text in a visually hidden span.
  • Mark unmonitored, releases and href as cosmetic, so changing them keeps every app's API key.
  • Increased contrast raises the secondary text; forced colors draw the kind bars in CanvasText and Today in Highlight. The shared loading placeholders now paint in forced colors.
  • Rows get the shared sliding hover highlight on a fine pointer and a pressed fill everywhere. initFluidHover takes an optional list with an optional zoom function, and placePill takes the page zoom so the pill stays on its row in a zoomed widget page.
  • Add the calendar glyph with a new upnext icon, and redraw the downloads icon as an arrow into a box.

Testing
All green, including the Docker build, image scan and e2e. Added 34 tests for the readers, series cache bounds, time zones, out-of-range rows, timeouts, partial failure, local sort, API key retention and the pill.

Changelog

Added

  • Up Next widget for Sonarr, Radarr and Lidarr.

Fixed

  • Widget loading placeholders show in high contrast mode.

Checklist

  • Stays within the project constraints: one container, no runtime dependencies, no build step (see CONTRIBUTING.md).
  • Tests added or updated for new logic, and the full suite, lint, and typechecks pass.
  • Docs updated if behavior or configuration changed.

Lists the next episodes, films and albums from up to six apps, soonest
first, with deep links to each item. Sonarr series records are fetched
per series and cached, so the calendar reply stays small. Include
Unmonitored is cosmetic, so changing it keeps every app key.
Up Next shows three agenda rows, each a day block, a kind bar and a title.
Downloads shows an arrow dropping into a box.
@SandObserver SandObserver added the enhancement New feature or request label Oct 25, 2026
One highlight moves between rows on a fine pointer, reusing the shared
fluid hover. Pressing a row deepens it, and on touch the press alone
shows. The moving pill now measures in the page's own units, so it
stays on its row inside a zoomed widget page. initFluidHover takes an
optional list of containers and items.
Keep date-only films and albums until their day ends at UTC-12 and sort rows in the reader's local time. Keep only short strings and bounded values in the Sonarr series cache. Skip rows whose runtime or date is out of range instead of failing every app. Name a 'Timed out' error a timeout. Report 90 days only when every longer read succeeded. Keep daily-show episode names that are not dates.

Show the failure caption in the empty state, use a neutral line when apps fail differently and read each app's problem aloud. Redraw rows only when their content changes and return focus to the same row. Pass the page zoom to placePill instead of measuring it, so unzoomed lists with fractional widths place the pill exactly.
@SandObserver
SandObserver merged commit 681c4e4 into main Oct 25, 2026
10 checks passed
@SandObserver
SandObserver deleted the feat/up-next-widget branch October 25, 2026 16:46
stackyard-release Bot pushed a commit that referenced this pull request Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant