Start from the example
- Open Tools → Plugins and press 📂 Open plugins folder. RadioMaster creates the folder, with a working example in
example-now-playing, and opens it. The window shows where the folder is. - Copy the example folder, rename it, and change its
plugin.jsonand script. - Press ⟳ Reload plugins. Your plugin appears in the list with a switch to turn it on or off.
- Press Send a test event to run it straight away. Anything it prints shows up in the plugin's Log.
plugin.json
Every plugin is a folder inside plugins with a plugin.json:
{
"name": "Now playing to Discord",
"description": "Posts every song to our #now-playing channel.",
"command": "python",
"args": ["discord.py"],
"events": ["track_started"],
"mode": "event"
}| Field | Meaning |
|---|---|
| name, description | Shown in the Plugins window |
| command, args | The program to run. It starts in the plugin's own folder |
| events | Which events it wants (below), or ["*"] for all of them |
| mode | "event" (the default) runs once per event. "service" starts with RadioMaster and keeps running |
Events
| Event | When | Extra fields |
|---|---|---|
| app_start | RadioMaster started | version |
| app_exit | RadioMaster is closing | |
| track_started | A song, voice track or jingle from the playlist started | title, artist, album, genre, year, path, duration, text |
| item_started | Another playlist row started (stream relay, line input, speech, teaser…) | title, text |
| playback_stopped | Playback stopped | |
| hour | The top of every hour | hour |
| encoder | A stream encoder connected, failed or stopped | encoder, name, state |
Every event also has event and time (ISO 8601).
How a plugin gets the event
- Event plugins get the event as one line of JSON on standard input, and as environment variables:
RM_EVENT,RM_TITLE,RM_ARTIST,RM_PATHand so on (each field in capitals withRM_in front). A run that takes longer than 60 seconds is stopped. - Service plugins get one JSON line on standard input per event, for as long as RadioMaster runs. When RadioMaster closes, standard input is closed: exit when that happens.
Control RadioMaster from a plugin
Print a line starting with RM: and RadioMaster runs it as a station command:
RM: STOP RM: VOLUME 60 RM: PLAYLIST Evening RM: ENCODER START 1 RM: RULE Station IDs RM: GENERATE Overnight
Examples
Write the current song to a file for OBS (Python)
import json, sys
e = json.loads(sys.stdin.readline())
open("nowplaying.txt", "w", encoding="utf-8").write(f"{e['artist']} - {e['title']}")Post to a Discord webhook (PowerShell)
$e = [Console]::In.ReadLine() | ConvertFrom-Json
$body = @{ content = "Now playing: $($e.artist) - $($e.title)" } | ConvertTo-Json
Invoke-RestMethod -Uri "https://discord.com/api/webhooks/…" -Method Post -Body $body -ContentType "application/json"with "command": "powershell", "args": ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "discord.ps1"].
Lower the volume at the top of every hour (a service, Python)
import json, sys
for line in sys.stdin:
e = json.loads(line)
if e["event"] == "hour":
print("RM: VOLUME 70", flush=True)Shell script (macOS and Linux)
printf '%s - %s\n' "$RM_ARTIST" "$RM_TITLE" > nowplaying.txt
Only install plugins you trust. Plugins run with your account's rights. While the app is connected to RadioMaster Server, plugins keep running on your own computer.
The remote control API
To control RadioMaster from another computer, a stream deck or a web page, turn on the remote control API in Settings → Remote API: tick Enable, choose the port (9258 by default) and an API password, then restart RadioMaster. Every call is a simple GET that answers with JSON:
| Call | Does |
|---|---|
| /api/status | State, artist, title, position, duration, volume, next and the playlist length |
| /api/play, /api/pause, /api/stop | Play, pause or resume, stop |
| /api/next, /api/prev | Next or previous |
| /api/volume?v=0.8 | Set the volume, 0 to 1 |
| /api/seek?s=30 | Jump to 30 seconds into the song |
| /api/cart?i=0 | Fire cart pad 1 (counting from 0) |
| /api/insert?path=… | Put a file after the song on air |
Add &pw=PASSWORD to every call when a password is set, for example:
curl "http://192.168.1.10:9258/api/status?pw=yourpassword"
The API is plain HTTP, so keep it on your own network.