# Resi Studio Cues Puts a live "time until the next Resi cue" countdown on the stage screen. **This folder is not a ProdDash tile.** It has no `module.json`, so the shell's module scan skips it. It lives here because this is where the production tooling lives, not because ProdDash loads it. That is also why it carries its own README, unlike the real modules, which are documented in the repo README's *Included modules*. --- ## What it does `resi_to_propresenter.py` watches a Resi decoder's playhead, works out how long until its next cue point, and keeps a ProPresenter countdown timer armed with that number. ProPresenter renders the countdown itself, so the stage screen is smooth and styled in whatever the stage layout uses, and nothing has to be pushed every second. The cue's name goes up as a ProPresenter stage message alongside it. The cue list and the playhead both come from Resi's cloud, not from the decoder — the decoder reports its position upstream, and `central.resi.io` hands it back. Nothing has to be installed at the decoder end. ## Why the playhead is estimated rather than displayed Resi republishes a decoder's `position` only every few seconds, on an irregular cadence, and each reading is already a little stale when it appears. Sent straight to ProPresenter, the countdown sits several seconds behind and lurches. So every reading is kept as *media time minus wall time*, and the **largest** recent value is the one trusted — that is the reading that reached us with the least delay, so a slow round trip or an unlucky poll cannot drag the countdown backwards. A reading that falls outside the link's measured noise floor is treated as a seek: the lock is dropped, the estimate snaps, and the cue list is re-read at once instead of on its timer. Playback is only called paused once the playhead has been still for clearly longer than Resi's own cadence, because a fixed timeout mistakes a slow update for a stop and freezes the countdown mid-service. How quickly a fired cue can possibly show on stage is bounded by how often Resi republishes the position. Nothing on this end beats that; the log prints the measured cadence so you can see what it is. ## Running it Settings live outside the checkout, at `~/Library/Application Support/ResiCues/config.json`, so a `git pull` never touches them. `config.example.json` here is the template. The Resi password is read from the Keychain and is never written to disk: security add-generic-password -a "you@yourchurch.org" -s resi-propresenter -w Then pick a decoder: python3 resi_to_propresenter.py --list and put its `playerHardwareId` into `player` in the config (leave it blank if the account has only one). `--dry-run` prints what it would send without touching ProPresenter. **Start it at login:** double-click `install-agent.command`. It writes a LaunchAgent that runs the script at login and restarts it if it stops, logging to `~/Library/Logs/resi-propresenter.log`. Run it again after a pull to repoint the agent. ProPresenter needs its network API on (Settings › Network) and a **countdown** timer whose name matches `timer_name` in the config — `NextCue` by default — placed on the stage layout, with a Message object for the cue name. ## Tests python3 test_playhead.py # the estimator against 9 simulated Resi profiles python3 test_end_to_end.py http://10.1.14.225:1025 `test_playhead.py` drives the estimator on a fake clock against a simulated Resi with a configurable update cadence, staleness, cadence jitter and network round trip; pass those four as arguments to run one profile. `test_end_to_end.py` runs the real script loop against a **real** ProPresenter with a simulated decoder, checks the timer is armed and counts down in step across a cue rollover, and puts ProPresenter back as it found it. Both suites are written so a deliberate break turns them red — six of seven mutations of the estimator do. Neither covers the live Resi calls, which need real credentials. ## The Companion sibling Before the stage-screen version, the same estimator shipped as a Bitfocus Companion module for Stream Deck buttons — a patched build of [reykroona/companion-module-resi-studio-cues](https://github.com/reykroona/companion-module-resi-studio-cues) (MIT), with the estimator, a PLAYING/PAUSED variable and resync actions added. It is not needed for the stage display and is not checked in here; the packaged `.tgz` and its patched sources are in `~/Desktop/Resi Companion/`. ## Resi's API Undocumented and unsupported — it is what `studio.resi.io` itself uses. Don't open a Resi ticket about it. Authentication is `POST /api/v3/login?newToken=true` with `{userName, password}`, which sets a `livingas1` cookie used as `Authorization: X-Bearer `; from there `/api_v2.svc/users/me`, `/api/v3/customers/{id}/venues`, `/api_v2.svc/users/{venueUuid}/players`, `/api/v3/customers/{id}/events/{eventId}` and `/api_v2.svc/streamprofiles/{profileId}/events/{eventId}/cues`.