Files
Nextcue/source/HELP.md
T

258 lines
9.4 KiB
Markdown
Raw Normal View History

# Resi Studio Cues (Bitfocus Companion Module)
This module logs into **studio.resi.io / central.resi.io** with a username + password, reads decoder/player playback position, loads cue points for the current event, and exposes variables/actions for cue timing and cue management.
The main goal is to drive things like a **countdown clock in ProPresenter** (time until next cue, next cue name, etc).
---
## Features
### Authentication
- Logs in via `POST /api/v3/login?newToken=true`
- Stores auth cookies (`refreshToken`, `livingas1`) and uses them on subsequent requests
- Exposes status via:
- Instance status (green/red in Companion)
- Variables: `auth_status`, `last_error`
### Player polling (live)
- Polls decoder/player position from:
- `GET /api_v2.svc/users/{venueUuid}/players`
- Updates variables like:
- `current_position`
- `current_position_sec`
- `current_event_id`
### Cue loading (per event)
When the current `eventId` changes, the module loads:
- Event detail:
- `GET /api/v3/customers/{customerId}/events/{eventId}`
- Captures `startTime` for ToD (time-of-day) math
- Cues:
- `GET /api_v2.svc/streamprofiles/{eventProfileId}/events/{eventId}/cues?canISetCues=1`
Cues are stored locally and used to compute **next/prev** cue timing from the live playback position.
### Cue timing variables
- Next cue:
- `next_cue_name`
- `next_cue_time_in_seconds`
- `next_cue_time_in_hms`
- `next_cue_position`
- `next_cue_tod` (24-hour)
- Previous cue:
- `prev_cue_name`
- `prev_cue_time_ago_in_seconds`
- `prev_cue_time_ago_in_hms`
- `prev_cue_position`
- `prev_cue_tod` (24-hour)
### Cue management actions
- Add cue (player position or custom time)
- Lookup cue by name (stores into `lookup_*` variables)
- Delete cue by name (looks up UUID, deletes by UUID)
---
## Installation / Testing
### Best (recommended): Developer Module via Git
1. Push this repo to GitHub/GitLab (public or private).
2. On the test system, add it as a Developer Module in Companion.
3. Restart Companion.
### Offline / manual
1. `yarn install`
2. `yarn build`
3. Zip the module folder (without `node_modules`) and provide to tester.
4. Tester places it in Companion’s modules folder and restarts Companion.
(Exact folder paths vary by OS / Companion version.)
---
## Configuration
Typical config fields:
- **Username / Email**
- **Password** (secret)
- **Default Player** (optional)
- **Polling intervals**
- Playback position refresh (fast, e.g. 2000ms)
- Account/venue refresh (slow, e.g. 60000ms)
- Cue refresh while playing (optional, e.g. 15000ms)
- **Fallback when no next cue** (optional)
> Note: dynamic "read-only" status display inside config is not supported by Companion config fields.
> Use Instance Status + module variables for connection state.
---
## Actions
- **Refresh profile**: Reload `/users/me`
- **Refresh lists**: Reload venues + players list
- **Select decoder/player**: Choose which player to poll
- **Add cue at player position (or custom time)**
- Options:
- Cue name
- Private cue
- Position source: player vs custom
- Custom time string
- Text fields support Companion variables (e.g. `$(internal:...)`)
- **Lookup cue by name**
- Writes result into:
- `lookup_cue_found`, `lookup_cue_uuid`, `lookup_cue_position`, etc.
- **Delete cue by name**
- Finds matching cue(s), deletes by UUID via:
- `DELETE /.../cues/{uuid}`
---
## Feedbacks (for button coloring)
Recommended “production” feedback set:
1. **Connected (auth OK)** → Green
2. **Error (auth/API)** → Red
3. **Player active** (position > 0) → Blue
4. **Approaching next cue** (threshold seconds) → Yellow
5. **Playback frozen** (position not changing) → Red
Playback frozen requires:
- variable `playback_last_change_epoch_ms` to be updated when playback position changes.
---
## Presets Included
### Status
- Connected / Error indicator
- Player active indicator
- Playback frozen warning
### Cues
- Next cue display (with T- countdown)
- Previous cue display
### Maintenance
- Refresh profile
- Refresh venues/players list
### Cue actions
- Add cue @ player position
- Add cue @ custom time
- Lookup cue by name
- Delete cue by name
---
## Notes / Limitations
- The Resi API endpoints used here are not public/stable; breaking changes may occur.
- Avoid polling cues every 2 seconds. Recommended cue refresh while playing is 10–30 seconds unless you have a specific need.
- Companion config fields are not truly read-only, so status is exposed via variables + instance status.
---
## Roadmap Ideas
- Optional periodic cue refresh while playing (rate-limited)
- Extra feedback: "No player selected"
- Extra feedback: "No next cue"
- More presets for ProPresenter integration workflows
---
## Playhead accuracy (0.1.0)
Resi only republishes a decoder's `position` every few seconds, on an irregular
cadence, and each reading is already slightly stale when it appears. Showing that
number raw makes the countdown jump in steps and sit several seconds behind.
This build instead keeps a running estimate:
- every reading is stored as **media time minus wall time**; the largest recent value
is the least-delayed reading and is the one trusted, so a slow round trip or an
unlucky poll can no longer drag the countdown backwards
- the display is recomputed **every second** from that offset, so the countdown ticks
smoothly between Resi's updates instead of stepping
- a reading that differs from the locked offset by more than the link's measured
noise is treated as a **seek** - the lock is dropped, the estimate snaps, and the
cue list is re-fetched immediately rather than on its timer
- playback is only called **PAUSED** once the playhead has been still for clearly
longer than Resi's own reporting cadence, so an irregular gap no longer freezes the
countdown
`position_update_interval_sec` reports how often Resi is actually updating. That
number is the floor on how fast a jump can possibly be noticed.
### Beating that floor
If cues are fired from Companion, the module does not have to wait for Resi to
notice. Add one of these to the same button:
- **Resync playhead to cue** - give it the cue name; the estimate moves there at once
- **Resync playhead to the NEXT cue**
The next real reading from Resi confirms or corrects it.
### Settings that matter
- **Player position poll (ms)** - 1000 is recommended. Accuracy no longer depends on
this, but a faster poll notices a jump sooner.
- **Cue list refresh (ms)** - 5000. Also forced immediately whenever a seek is seen.
- **Position trim (ms)** - leave at 0. Only needed if the whole pipeline is
consistently behind; positive values push the estimate forward.
## Startup fix (0.1.2)
On a Resi that publishes every ~30s, the module could start a few seconds before a
publish and learn a 2s cadence from that partial first gap. It then threw out every
real 30s gap, so `playback_state` flipped to **PAUSED** 15s into each update - the
countdown froze and the next cue lagged, worst with cues close together.
- the partial gap after startup (or after a manual resync) is no longer learned
- a single outlier gap can no longer lock out the real cadence
- until the cadence is measured, PAUSED waits 45s instead of 15s
## Resi login back-off (0.1.3)
0.1.2 retried a failed Resi login on every player poll (once a second, for ever), and
answered every 401/403 by signing in again. With a wrong password, a rate limit or a
login that may not see decoders, that is thousands of sign-ins an hour: Resi replies
with 429 and then locks the account (it locked one at North Attleboro).
- after any failed login, or a 429 on any request, every Resi call holds off: 15s,
doubling to 5min, or as long as Resi's Retry-After asks
- a 401/403 renews the session only if it is over a minute old; a refusal straight
after signing in is a permission ("ask a Resi admin for access") and holds off
- status and `last_error` say which: locked (USER_LOCKED), rate-limited, password
rejected, no access, or unreachable
- the log says it once per problem, not once a second
- the cache-busting parameter is no longer dropped for good on a 401/403/429
## Start-up never crashes on a Resi problem (0.1.4)
In 0.1.3 a failed Resi login at start-up (here: a locked account) made the module's
init fail. Companion counts that as a crash and restarts the module every few
seconds, and each restart signed in again from scratch, outside the hold-off.
- init no longer fails when Resi refuses or is down: it logs "Not connected to Resi
yet … will keep trying", starts the account poll, and the hold-off paces retries
- once Resi answers, the configured decoder is picked up automatically
- saving new credentials clears the old hold-off and starts over
## Settings that always save (0.1.5)
While the connection wasn't connected to Resi, its settings couldn't be saved at all:
the saved decoder showed as "??" because the list only fills once Resi answers, and a
cue refresh that had never been saved showed as 0, below its minimum. Either one blocks
Save in Companion, including the login change that would have fixed the connection.
- the saved decoder is always offered, as "(not connected to Resi yet)" until Resi answers
- an upgrade step fills any setting an older connection never saved with its default
- event details are read once per event instead of on every cue refresh, which is one
Resi request fewer every few seconds
- cue requests share the login/rate-limit hold-off, and "Loaded N cues" and repeated
cue-refresh failures are logged once, not every few seconds