The public /screen archive ("Movie Nights", beta): each entry is a screened film named from its soundtrack, with the date and song count Public Movie Nights archive · July 2026

  • When the pub screens a film, the bar-right TV shows a “Now Showing · card and the public /screen page archives the night — automatically, with no operator action in the common case.
  • When an identified soundtrack album is named for the film, setlist.album supplies the candidate film title. This works only for music-identifiable films such as musicals, concert films, music documentaries, and scored films with soundtrack album metadata.
  • Dialogue-driven films and anything the audio can’t name fall back to a generic “On the big screen”, or the operator types the title (see Operator path).

Sources: worker.js (tickScreenings wiring, computeNowShowing, handleScreenPage, handleScreeningsApi), worker/lib/pub-screenings/{detect,store,state-machine}.js, public/tv/cinematic.js, migrations/0046_pub_screenings.sql


How detection works

  1. Open (audio). A 60-second cron (tickScreenings) watches the recent setlist. When N or more plays (rows, not distinct titles) share one normalized album within a 20-minute window, it opens a candidate screening. Counting rows is deliberate: a single film can play few distinct titles many times.
  2. Confirm (automatic). A candidate is promoted to confirmed when either:
    • the projector is freshly on — the Pi’s heartbeat reports projector_status.power == "on" and the heartbeat is recent (a stale, frozen “on” after a Pi outage does not confirm), or
    • a Notion event today has a title that matches the film.
    • Projector power is the only device gate — a phone mirroring an app over HDMI reads as “video” to the matrix, so that signal is intentionally ignored.
  3. Re-tag. On confirm/close, the songs played during the screening window are re-tagged from content_kind='music' to 'video' so they leave Top Songs / The Vibe / Persona (they’re part of a movie, not the music charts). They’re stamped with a stable screening_id so a later title edit or a re-screening of the same film never mis-targets the reversal.
  4. Close. After the screening goes quiet (no same-album plays for ~35 min) the screening closes and lands in the /screen archive. A different film starting mid-stream force-replaces the current one (double-feature safe).

A candidate that never confirms is abandoned with no re-tag — if it was just someone playing a soundtrack album as bar music, nothing is shown and the charts are untouched.


Bar TV card

  • On the bar-right TV, a confirmed screening leads the silent rotation with “Now Showing” (eyebrow) + the film title (large Playfair) + the poster rendered as a soft, dark-scrimmed background bloom behind the title (legible across a dim room; the title is the glanceable signal, not a small thumbnail).
  • No poster → title-only. A live song always preempts the card (the song card wins), and the movie card returns when the music stops.
  • The card only appears for a confirmed screening (the named film) or when the Pi’s live audio verdict is actually video (the generic “On the big screen” / a live game). A projector that’s simply powered on but idle does not light a card — “the screen is on” alone isn’t “something’s showing.”

/screen — the public archive

  • pub.ihnyc-rc.org/screen — a top-level page reached from the homepage (a peer of the music surfaces, not nested under /setlist). A reverse-chronological, month-grouped list of past screenings: poster, film title, the night, and the soundtrack track count. Tap a night to expand its tracklist.
  • An amber “Now Showing” strip appears at the top while a screening is live.
  • Empty state, broken-poster fallback (a title-on-dark placeholder tile), and 0-track nights are all handled.

Operator path (the long tail)

  • For a non-musical film, an off-Notion night, or a night the projector heartbeat is flaky, the auto-detector won’t open a candidate. The operator names it manually: /admin/now-showing → “Movie title…”, type the film (poster optional — auto-looked-up if blank). This both shows the card and creates the screening for /screen.
  • A revert (“this wasn’t a movie”) un-tags a screening’s songs back to music: POST /api/admin/screenings/:id/revert (admin-gated).

Rollout & configuration

The feature is off until enabled, gated by two flags:

FlagValuesPurpose
SCREENINGS_ENABLEDoff (default) · shadow · onshadow opens candidates and logs [pub-screenings] cron lines but does not re-tag songs or show a card — a safe tuning window with zero analytics impact. on goes live.
NOW_SHOWING_ENABLEDflagMust be on for the bar-TV “Now Showing” card to render (shared with the sports/now-showing card).
TMDB_API_KEYsecret (optional)Real film posters via TMDB. Without it, Deezer album covers are used (keyless). Both report to /admin/api-health.

Recommended order: apply the migration → set SCREENINGS_ENABLED=shadow → run a real movie night and watch wrangler tail for [pub-screenings] (openedconfirmed) → if the threshold looks right, set SCREENINGS_ENABLED=on and ensure NOW_SHOWING_ENABLED is on.

Migration (manual)

wrangler d1 execute SETLIST_DB --local  --file=./migrations/0046_pub_screenings.sql
wrangler d1 execute SETLIST_DB --remote --file=./migrations/0046_pub_screenings.sql

Additive and nullable-safe (new pub_screenings table, setlist.screening_id, a seeded tmdb api-health row) — dormant until the flag flips, so applying it changes nothing on its own.