Skip to content

Add Arr Coming Soon app - #678

Draft
nsluke wants to merge 4 commits into
tronbyt:mainfrom
nsluke:arr-coming-soon
Draft

Add Arr Coming Soon app#678
nsluke wants to merge 4 commits into
tronbyt:mainfrom
nsluke:arr-coming-soon

Conversation

@nsluke

@nsluke nsluke commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

What your self-hosted media stack drops next: tonight's episodes from Sonarr, or this week's releases from Radarr.

The tronbyt crowd overlaps heavily with the *arr crowd — Jellyfin, Plex and Immich apps are among the most active recent additions — but there are no Sonarr or Radarr apps in the catalog at all.

Screenshots

Tonight (Sonarr) This week
tonight week
Radarr All caught up
radarr caught

Data

Your own instance, your own API key, over your LAN — /api/v3/calendar on either service with the X-Api-Key header. Nothing leaves your network.

The v3 contract was verified against both projects' published OpenAPI specs, fetched live from GitHub rather than recalled. What that turned up:

  • Nullability is pervasive. Sonarr's title, series.title and airDateUtc, and Radarr's title, inCinemas, digitalRelease and physicalRelease are all nullable. Every one is handled.
  • includeSeries defaults to false on Sonarr — without passing it explicitly there is no series title to show at all.
  • Radarr release dates are midnight-UTC stand-ins for plain dates, so the app uses the yyyy-mm-dd prefix unconverted. Sonarr's airDateUtc is a real instant and is converted through your timezone — a 01:00Z air time is tonight in the US, and that boundary is exercised by a fixture with a 21:00 ET episode.

Empirical pixlet probing also found that time.parse_time aborts on regex-passing but out-of-range values (hour 99, month 13, Feb 30, second 61) while time.time() quietly normalises them. That exposed two latent crash paths, both fixed: every timestamp is range-checked before caching, and the JSON decode uses a default so an array-shaped non-JSON body can't abort.

Verification

17 states: tonight, this week, both Radarr variants, all-caught-up, the days=1 clamp, a 401 auth card, HTTP 500, an HTML body, and five hostile-payload shapes including out-of-range timestamps and null titles.

pixlet check passes under the repo's pinned v0.50.1. Default render 10 ms, zero network — the unconfigured demo card uses fictional titles and is labelled DEMO.

Adversarial review caught three real display bugs, all reproduced first: the hasFile green pip was drawn on top of the air time (12:00AM rendered as 2:00AM); the TONIGHT panel filled with episodes that had already aired that morning, pushing tonight's actual episode behind the "+N more" counter; and an unreachable server with an aged-out cache rendered a confident "ALL CAUGHT UP" instead of "can't connect".

Caveats

  • Never tested against a real Sonarr or Radarr instance — there's none on this network, so this is built to the OpenAPI specs and a spec-faithful stub. Untested real-world paths: reverse-proxy auth redirects, urlbase sub-paths (the base is rstrip'd and the path appended, but unproven), and self-signed HTTPS (pixlet will refuse it).
  • The manifest name is Arr Coming Soonpixlet check enforces title case and a 17-character limit, so "Coming Soon for Sonarr/Radarr" doesn't fit. The full name lives in the description.
  • Extraction caps at 40 items, so the "+N" counter tops out there.
  • A true transport error still aborts the first render uncatchably; the pre-written gate makes every render within the next 60 s serve cache or the fallback card.

🤖 Generated with Claude Code


64x64 square panel support

The square holds twice the list rather than the wide layout with room underneath: under the same header and rule, its 56 body rows divide into four 14px slots, so 8 + 4x14 = 64 fills the panel to its last pixel row and four items show instead of two. Header, rule, row design, fonts, service accent colours and the hasFile pip are pixel-identical to wide; what changes is the row count and the "+N" chip now counting from the fourth row. Status cards (CAN'T CONNECT / CHECK API KEY / ALL CAUGHT UP) get the whole body box so they centre instead of hugging the top edge.

square 64x64

The wide layout is untouched. An additive is_square() branch on canvas.size() (h * 2 > w + 16, matching the convention in #655/#666 — shape, never size, so a 2x wide panel is never mistaken for a square one). Wide output was rendered before and after the port and compared byte for byte: 264 comparisons across configs at both 64x32 and 128x64, zero differences, with a deliberately broken copy used as a negative control to prove the comparison actually discriminates. pixlet check green on the pinned v0.50.1. No manifest change — upstream has no supports64x64 field.

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

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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

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