A Bitfocus Companion module for FoShow, a macOS broadcast playout application. The module drives FoShow through its HTTP/JSON control surface and mirrors FoShow's live state back into Companion variables and button feedbacks.
Built against the Companion 4.x SDK (
@companion-module/base2.x /node22runtime).
- Transport: Play, Pause, Play/Pause toggle, Stop, Next, Previous, Jump to In/Out-point, Seek.
- Cueing: Cue any clip from a dropdown that stays in sync with the current playlist.
- Playlists: Switch between playlists from a dropdown of everything FoShow knows about, by name, or step Next/Previous; toggle loop.
- Reorder-proof cueing: Cue Clip by Name matches on file name so buttons survive playlist edits.
- Countdown:
next_clip_name+time_remainingvariables and a "time remaining is below" feedback for hand-off warnings. - Lockout: engage FoShow's lockout mode from a button; feedback lights red while it is on.
- Audio: Set volume (0–100 %), set mute, toggle mute.
- DSK: Fade to Black / Restore from Black with configurable durations.
- Live feedbacks: playing, blacked-out, transitioning, ready-to-play, muted, on-air clip, loaded playlist.
- Variables: clip name, playlist name, timers (
m:ss/h:mm:ss), volume, mute state, lockout, next clip, and more. - Preset pack so a fresh install has useful buttons immediately.
- Bonjour auto-discovery of
_foshow._tcpinstances on the LAN (optional).
- In FoShow, open Settings → Remote Control, enable the HTTP API and note the port (default
7878) and API token. - In Companion, add a new connection and search for FoShow.
- Enter the Host/IP of the Mac running FoShow and paste the API token.
- Or pick the instance from Auto-discover (Bonjour) if it's on the same LAN.
- The connection goes green once Companion reads
/status. The Companion log will show the FoShow app version on first connect.
See companion/HELP.md for the full reference.
| Action | Options | Description |
|---|---|---|
| Play | — | Start playback |
| Pause | — | Pause playback |
| Play/Pause Toggle | — | Toggle between play and pause |
| Stop | — | Stop and reset to beginning |
| Next item | — | Jump to the next item in the playlist |
| Previous item | — | Jump to the previous item |
| Jump to In-point | — | Seek to the current item's in-point |
| Jump to Out-point | — | Seek to the current item's out-point |
| Cue Clip | Clip (dropdown) | Load a specific clip by position |
| Seek | Position (seconds) | Seek to an absolute time |
| Set Volume | Volume 0–100 % | Set master output volume |
| Set Mute | Muted on/off | Set mute state explicitly |
| Toggle Mute | — | Toggle mute on/off |
| Fade to Black | Duration (s) | Fade output to black (default 1.0 s) |
| Restore from Black | Duration (s) | Clear the black overlay (default 0.5 s) |
| Switch Playlist | Playlist (dropdown) | Load a different playlist |
| Switch Playlist by Name | Name (text, variables ok) | Load a playlist by name (unique prefix ok) |
| Next Playlist | — | Step to the next playlist (no wrap) |
| Previous Playlist | — | Step to the previous playlist (no wrap) |
| Playlist Loop | Toggle / On / Off | Set the current playlist's loop flag |
| Cue Clip by Name | Clip (dropdown, custom ok) | Cue by file name; survives reordering |
| Lockout | Toggle / On / Off | FoShow refuses all playback commands while on |
| Feedback | Description |
|---|---|
| Playback is running | True while FoShow is playing |
| Output is faded to black | True while the DSK overlay is active |
| Transition in progress | True during a crossfade |
| Ready to play | True when a clip is cued and ready |
| Audio is muted | True while master audio is muted |
| Clip is on-air | True when the item at a given index is current |
| Playlist is loaded | True when the selected playlist is active |
| Lockout is on | True while FoShow is in lockout mode |
| Playlist loop is on | True when the current playlist loops |
| Time remaining is below | True with fewer than N seconds left (optionally only while playing) |
| Variable | Type | Description |
|---|---|---|
$(FoShow:is_playing) |
0/1 | Playback running |
$(FoShow:is_blacked_out) |
0/1 | DSK overlay active |
$(FoShow:is_transitioning) |
0/1 | Transition in progress |
$(FoShow:is_ready_to_play) |
0/1 | Clip cued and ready |
$(FoShow:is_muted) |
0/1 | Master audio muted |
$(FoShow:master_volume) |
0–100 | Master volume as a percentage |
$(FoShow:current_item_index) |
integer | 0-based index of the current item |
$(FoShow:current_clip_name) |
string | Filename of the current clip |
$(FoShow:current_playlist_name) |
string | Name of the loaded playlist |
$(FoShow:current_time) |
m:ss | Playhead position (h:mm:ss past an hour) |
$(FoShow:duration) |
m:ss | Current item duration |
$(FoShow:time_remaining) |
m:ss | Time remaining in the current item |
$(FoShow:time_remaining_seconds) |
float | Time remaining in seconds (raw) |
$(FoShow:active_channel) |
a/b | Active A/B player channel |
$(FoShow:next_clip_name) |
string | Clip FoShow will advance to (empty at end of a non-looping playlist) |
$(FoShow:next_item_index) |
integer | 0-based index of the next item, -1 if none |
$(FoShow:current_end_action) |
string | advance, loopItem, holdLastFrame or fadeToBlack |
$(FoShow:is_locked) |
0/1 | Lockout engaged |
$(FoShow:playlist_loops) |
0/1 | Current playlist loops |
| State | Meaning |
|---|---|
| OK (green) | /status is being polled successfully |
| Connecting | First poll in progress after (re)configuration |
| Bad config | Missing host/token, or the token was rejected (HTTP 401) |
| Connection failure | Host unreachable / timed out; retries with exponential backoff up to 5 s |
corepack enable # this module uses yarn 4 via corepack
yarn install
yarn lint # prettier --check + eslint
yarn format # prettier --write
yarn package # build the installable .tgz with companion-module-buildThe module is plain JavaScript, one file per concern:
| File | Responsibility |
|---|---|
src/main.js |
Instance class: config, lifecycle, polling, dynamic dropdowns |
src/api.js |
HTTP client — single request() helper, bearer auth, typed errors |
src/actions.js |
Action definitions |
src/feedbacks.js |
Boolean feedbacks (read from cached status) |
src/variables.js |
Variable definitions + value/formatting helpers |
src/presets.js |
Starter preset pack |
Connection settings — host, port, API token and optional Bonjour discovery:
Preset pack — drag any of these onto a button; feedbacks light live (here FoShow is playing, so the Play/Pause toggle and Now Playing are green):
Example page built entirely from the presets, with the countdown and Next Up buttons tracking the running clip:


