TS Rail is a small TeamSpeak activity rail daemon for stream overlays. It connects to the TeamSpeak ClientQuery interface, tracks who is present in a target channel, and exposes an HTTP endpoint (/state.json) plus a ready-made overlay at /overlay/ that you can drop into OBS as a browser source.
- ClientQuery bridge to the TeamSpeak client (auth via API key).
- State tracking for clients in a channel: nickname, UID, talking state, approved/ignored flags.
- Policy controls (auto-mute unknowns, approval gating, ignored users, target channel).
- HTTP service for overlay data and static assets.
- Control socket for a lightweight CLI workflow.
For protocol and overlay details, see DESIGN.md and OVERLAY.md.
- Python 3.8+ (asyncio-based daemon).
- A TeamSpeak client with ClientQuery enabled (default on
127.0.0.1:25639). socatforscripts/tsrailctlconvenience commands.
-
Clone the repo and run the daemon:
scripts/tsrailctl service-start
-
Set the ClientQuery API key (retrieve that info from the TeamSpeak client):
scripts/tsrailctl setkey YOUR_API_KEY
-
Check status:
scripts/tsrailctl status
-
Open the overlay in a browser (or OBS browser source):
http://127.0.0.1:17891/overlay/
Config and data are stored in the user’s home directory:
~/.config/tsrail/config.json~/.config/tsrail/clientquery.key~/.local/share/tsrail/assets/
A minimal config.json looks like this:
{
"approved": ["UID1", "UID2"],
"ignored": ["UID3"],
"policies": {
"auto-mute-unknown": true,
"require-approved": true,
"target-channel": 7,
"show-ignored": false,
"include-bot": false
},
"http": { "host": "127.0.0.1", "port": 17891 },
"clientquery": { "host": "127.0.0.1", "port": 25639 }
}You can update these values via the control socket (tsrailctl policy, approve-nick, etc.) and they will persist. Use policy include-bot true if you want the daemon’s own client to appear on the rail (avatars will load from the bot’s UID folder, or assets/users/bot/ if the UID is not yet known).
scripts/tsrailctl is a helper that talks to the UNIX control socket:
scripts/tsrailctl status
scripts/tsrailctl key-status
scripts/tsrailctl channels
scripts/tsrailctl approve-nick "Streamer Name"
scripts/tsrailctl ignore-uid <uid>
scripts/tsrailctl policy target-channel "OBS Audio"
scripts/tsrailctl dump-stateThere are also service helpers for a basic user-space daemon workflow:
scripts/tsrailctl service-start
scripts/tsrailctl service-stop
scripts/tsrailctl service-statusThese expect the repo to live at ~/tsraild and log to ~/.local/share/tsrail/tsraild.log.
Assets are served from ~/.local/share/tsrail/assets/ and can be overridden per user. The daemon accepts avatar assets in svg, png, apng, gif, webp, and avif formats, so animated GIF/APNG avatars are supported. When an approved user first appears in the rail, the daemon creates assets/users/<uid>/ and seeds it with default avatar.svg and avatar_talk.svg if no avatar files exist yet.
Recommended layout:
assets/frames/tv_idle.png
assets/frames/tv_talk.png
assets/users/<uid>/avatar.png
assets/users/<uid>/avatar_talk.gif
If a talk asset is missing, the idle asset is reused. You can replace avatar assets live under ~/.local/share/tsrail/assets/ and the next /state.json poll will reflect the new files. Default example assets live in the repo’s assets/ directory.
- The overlay contract is defined in
OVERLAY.md. - The daemon behavior and policy hooks are described in
DESIGN.md. - This repo is pure Python + static web assets; no binary files should be added.
TBD.
