Both chats, live numbers, and viewer song requests in one tab.
Everything your stream needs in one browser tab: chat from Twitch and TikTok side by side, live numbers, and a music box your viewers load songs into. It runs on your PC and quietly lives in the system tray.
Local first: internet is only needed for the chat feeds, YouTube search, and audio. Everything else stays on your PC.
| Feature | Description |
|---|---|
| Both chats, one column | Twitch and TikTok newest-on-top, with platform badges and a shield for mods |
| Faces + profiles | Every chatter shows their profile picture (or an initial disc when none is found); click a name to open their Twitch/TikTok profile |
| Translate | Select any message, right-click, translate it to English (source language shown) |
| Stickers | TikTok fanclub stickers and pasted sticker images render inline in chat |
| Quiet bot | Only song requests appear in the feed. Nothing is ever written to your Twitch or TikTok chat |
| Clear chat | Hold the button (it fills as you hold) to wipe the on-screen feed |
Viewers, likes, gifts (with diamond value), follows, shares, joins. They update as they happen. Joins count first-timers only. Rejoins are skipped, and new joiners get a feed line.
| Feature | Description |
|---|---|
| Viewer requests | Viewers type !sr song name in chat, the song lands in the queue and plays. Toggle Requests on/off anytime (saved, stays as set after restart) |
| Background player | Music runs in mpv, its own app with its own sound. Capture it in OBS as a normal channel |
| Keeps playing | Close the tab or the browser and it keeps going; reopen and it shows exactly where it is |
| Crossfade | True overlap: the next song starts on a second player while the current fades out (toggle Xfade; length in Music.CrossfadeSeconds, default 4s) |
| Full transport | Play, pause, previous, skip, volume, scrub bar (drag or arrow keys nudge 5s) |
| EQ & loudness | Slim 10-band equalizer (plus Flat / Bass+ / Vocal / Club presets) and a loudness switch, both saved |
| Library lists | History, liked, and blocked songs live under the player |
| Undo an unlike | Unliking a song leaves it on the list for a minute with a countdown, so a misclick is recoverable. undo puts it back, x clears it now, or it goes on its own |
| Radio fallback | When the queue runs out, a similar song plays, shuffled from the related mix (same artist won't loop) and preloaded before the current ends, so a skip is instant instead of waiting on a fetch. Turn "radio off" to stop instead |
Drag the chat, stats, and music panels by their title bars into any order. It remembers for next time.
- Windows 10 / 11
- Internet (chat feeds, YouTube search, and audio run online; everything else stays local)
- OBS (optional, for capturing the music channel and showing the queue overlay)
- Grab the newest zip from the releases page and unzip it anywhere.
- Run
StreamerHub.exe. The dashboard opens in your browser; the app sits in the system tray. - A first-time setup walks you through pointing it at your accounts: your Twitch channel and TikTok username (no
@). The lights in the top bar show when they connect.
Needs the .NET SDK and Node.js. Clone the repo and run build.bat. The output is dist\StreamerHub.exe. (Developers: install.bat installs it to %LOCALAPPDATA%\StreamerHub with a Start Menu shortcut instead.)
The app checks for updates on its own and shows a chip in the top bar when one is ready:
| Action | How |
|---|---|
| Check now | Click the version chip → check |
| Install | Click the update button. It downloads, verifies, swaps itself in, and restarts. Music resumes where it was |
| After updating | The dashboard tab reloads itself into the new version |
Your settings and lists survive every update. If anything ever goes truly sideways, redownload the zip and drop your old Config.json next to the new exe so you keep your channel names.
| Action | How |
|---|---|
| Add a song | Search box, type a name, Enter. play starts it now, + queue lines it up |
| Reorder the line | Drag queue rows up or down |
| Jump around a song | Drag the thin bar under the title, or arrow keys nudge 5 seconds |
| Controls | Play/pause, previous, skip, replay (restarts the song), loop toggle (replays the song until turned off), volume slider |
| Space bar | Toggles play/pause from anywhere except a text box, so your hands can stay off the mouse |
| Skip without the jolt | Skipping and stopping fade the sound out over a moment instead of cutting dead |
| EQ & loudness | Under the player, saved automatically |
| Unlike by accident | The song stays in liked for a minute, dimmed, counting down. undo restores it, x removes it now |
Viewers request songs with !sr plus a song name (links are rejected, names only). Requests are skipped when longer than MaxTrackMinutes, when the queue is full, or when the same viewer asks again too fast.
| Action | How |
|---|---|
| Rearrange | Drag panels by their title bars (chat / stats / music) |
| Resize activity | Drag the divider above the activity feed up or down |
| Change theme | Gear icon → themes (amber, rose, mint, violet, blue, rgb, or Custom with your own color) |
| Colorblind mode | Gear icon → themes → colorblind mode (off, protanopia, deuteranopia, tritanopia). Converts your picked accent to the nearest color the deficiency can tell apart (safe colors stay as picked), on your dashboard and the stream overlay. Off restores your theme |
| Open it again | Double-click the tray icon (or run the exe again, which opens the dashboard if already running) |
| Stop it | Right-click the tray icon → Quit |
Switch anytime in the gear menu. The accent follows the theme everywhere (live tile, progress bar, update chip):
Pick Custom for any accent color (shade pad, hue slider, presets, or paste a hex). The stream overlay follows it too.
Show the live queue on stream: add a browser source in OBS pointing at http://127.0.0.1:51324/overlay.html. Transparent background, current song plus what's queued (long queues auto-scroll five at a time, long titles glide through). Compact enough to tuck in a corner. It follows your dashboard theme automatically.
Config.json lives next to the app (the setup wizard and the settings gear both write it too). Change it by hand, save, reopen the app. Done.
{
"AppName": "StreamerHub",
"Layout": "CSM", // panel order: C = chat, S = stats, M = music
"Port": 51324, // the number used in the page address
"AllowNetwork": false, // true = open the dashboard to the local network (phone section below)
"AutoOpenBrowser": true, // true = the page opens once on first run (tray icon reopens it later)
"Theme": "amber", // amber, rose, mint, violet, blue, rgb, or custom
"ThemeColor": "", // your own accent, only used when Theme is "custom"
"CbMode": "off", // off, protanopia, deuteranopia, tritanopia
"Twitch": {
"Channel": "your-channel-name", // your Twitch channel name
"ClientId": "", // optional: for Twitch viewer count, see below
"ClientSecret": "", // optional: same
"PollViewersSeconds": 45 // how often to count Twitch viewers
},
"TikTok": {
"Username": "your-tiktok-name", // your TikTok name, no @
"CustomSigningServer": "", // optional, for flaky TikTok connections
"SigningServerApiKey": ""
},
"Music": {
"Command": "!sr", // the word in chat that requests a song
"YtDlpPath": "", // leave empty to use the yt-dlp in tools
"YtDlpCookiesFile": "", // optional: full path to a cookies.txt if YouTube blocks searches
"YoutubeApiKey": "", // optional override; blank = the app picks the key up itself
"DefaultVolume": 25, // how loud new songs start
"MaxTrackMinutes": 10, // longest song a request can be
"MaxQueueLength": 20, // song line limit
"MaxQueryLength": 100, // how long a request text can be
"RateLimitSeconds": 15, // wait between requests per viewer
"GlobalCooldownSeconds": 5, // pause between requests from chat
"AutoNextRadio": true, // true = a similar song plays when the queue runs out
"LoopOne": false, // true = replay the same song until turned off
"RequestsOpen": true, // true = viewers can request songs with !sr
"ModVolume": true, // mods may set volume from chat (!volume)
"ModRequests": true, // mods may open and close requests (!requests)
"ModTransport": true, // mods may pause and resume (!play / !pause)
"ModSkip": true, // mods may skip and remove songs (!skip / !revoke / !dq)
"MpvPath": "", // leave empty to use the mpv in tools
"AudioDevice": "", // empty = your default sound output; set one for a specific device
"Equalizer": [0,0,0,0,0,0,0,0,0,0], // 10-band EQ, each band -12 to +12
"Loudness": true, // true = smooth out the sound for streaming
"Crossfade": true, // true = overlap the next song over the ending one
"CrossfadeSeconds": 4 // overlap length in seconds (0.5 to 12)
},
"Updater": {
"Enabled": true, // the built-in update checker
"Feed": "https://raw.githubusercontent.com/Vider7/StreamerHub/main/version.json",
"AutoCheckHours": 2.0 // how often to check, in hours
}
}
The app also writes your saved state here, so these appear once you use the dashboard:
| Key | What it holds |
|---|---|
Music.LastPlayed |
The song playing when you closed the app, and how far in it was. This is what makes it resume |
Music.Queue |
Songs waiting in line |
Music.Liked |
Songs you liked |
Music.Blocked |
Songs you blocked, so they never play again |
BrowserOpened |
Set once the page has opened, so first run only opens it one time |
Hand-editing is fine while the app is closed. The app rewrites this file as it runs, so edits made while it's open get lost.
Chat works with no key at all; without one the dashboard just shows "viewer count off" for that tile, and Twitch avatars load through a public fallback service. Want the number (plus direct Twitch profile pictures)? Register an app at https://dev.twitch.tv/console/apps, paste its Client ID into Twitch.ClientId and Client Secret into Twitch.ClientSecret, save, reopen.
Every song resolves through yt-dlp, which takes a couple of seconds. There is a faster route using YouTube's own public player key, and the app picks that key up by itself at startup (the log says auto key: picked up from youtube page), so there is normally nothing to do.
Music.YoutubeApiKey is an optional override if you want to pin a specific key. Leave it blank to let the app find its own. You never need to copy a key by hand: the value is the public INNERTUBE_API_KEY that YouTube serves to every page, not an account secret.
If a fast resolve ever fails or the URL will not play, the app re-resolves through yt-dlp in the same request rather than dropping the song, and repeated failures switch it off for ten minutes on their own. You can watch this happen in logs\app.log:
| Log line | Meaning |
|---|---|
fast resolve <id> via auto: ok in 140ms |
The fast route answered |
stream <id>: upstream 403 on fast(auto) url, re-resolving via yt-dlp |
Fast URL would not serve, fell back |
fast path disabled for 10 min after 2 failures |
Breaker tripped, yt-dlp only for now |
About the override: if you paste a key and it is the wrong length or otherwise not working, the app still tries it and then falls back to its own key automatically, so a bad paste will not break music.
- Play a song once (so the background player is running).
- In OBS, add an Application Audio Capture source and pick the mpv entry.
- The song now has its own fader, mute button, and routing, like any other source. Keep the dashboard volume fairly high and use the OBS fader for stream level.
No window to capture: the player has no UI. If Application Audio Capture is missing on your Windows version, fall back to Audio Output Capture, or set Music.AudioDevice to send music to its own output device.
- In
Config.json, set"AllowNetwork": true, save, reopen the app. - The app opens the firewall port itself on startup. If the log says it couldn't, right-click
StreamerHub.exe→ run as admin once, then normally after that. - On your phone (same Wi-Fi), open
http://<your-pc-ip>:51324(port changes if you changedPort).
Finding your PC's IP, two ways:
- Easiest: open
logs\app.lognext toStreamerHub.exeand look for theon your network: http://...lines. That's the exact address to type. - Or press
Win+R, runcmd, typeipconfigand read the IPv4 Address under your Wi-Fi adapter (usually192.168.x.x).
Only on networks you trust: anyone on the network gets the full dashboard, including playback control. Leave AllowNetwork at false (the default) to keep it on the PC only. Flip it back to false and restart to remove the firewall rule again (needs admin once, same as creating it).
Run it like an app: open the dashboard on your phone, then iPhone Share → Add to Home Screen (Android: menu → Add to Home screen). It launches standalone with its own icon, no browser tab, no pull-to-refresh.
Remote behavior: phones show one panel at a time behind the burger menu (top-left), skip the setup wizard and update chip, and follow the house theme. The PC stays the main screen and every change applies to the one shared state.
| Symptom | Fix |
|---|---|
| Not sure what's happening | Read the status text at the bottom of the page and the lights in the top bar |
| No music | Make sure mpv.exe is in tools\mpv next to the app, then play a song |
| Check says up to date right after a release | Wait a few minutes and check again. The update feed takes a moment to refresh |
| Need help from a friend | Send them logs\app.log from the app folder, usually everything they need |
Source code is in StreamerHub/ (C# server) and web/ (React dashboard). Build with:
build.bat
Output: dist\StreamerHub.exe. Requires the .NET SDK and Node.js. To ship a release zip + update feed, run package.bat (see scripts/README.md).


