A high-performance, race-condition-free streaming manager for Twitch, YouTube, and Holodex.
git clone https://github.com/yourrepo/LiveLink
cd LiveLink/rust
cargo build --release
Create config/ directory with JSON files:
mkdir -p config
# Override config file values
export HOLODEX_API_KEY="your-key"
export TWITCH_CLIENT_ID="your-id"
export TWITCH_CLIENT_SECRET="your-secret"
export YOUTUBE_API_KEY="your-key"
export LIVELINK_CONFIG="/custom/config/path"
export LOG_LEVEL="debug"
export PORT="3001"
# Server mode
cargo run
# CLI mode
cargo run -- stream list
cargo run -- screen enable 1
All config files go in config/ directory.
favorites.json β Favorite ChannelsFormat A: Per-platform (recommended)
{
"holodex": {
"default": [
{ "id": "UC3n9mTfC7Ib1P8Z-MqP5M8w", "name": "Mori Calliope", "score": 100 },
{ "id": "UCf5mFVsGjJ5y2qW9T5s5j5A", "name": "Gawr Gura", "score": 95 }
]
},
"twitch": {
"default": [
{ "id": "monstercat", "name": "Monstercat", "score": 80 },
{ "id": "sodapoppin", "name": "Sodapoppin", "score": 75 }
]
},
"youtube": {
"default": [
{ "id": "UCXuqSBlHAE6Xw-yeJA0Tunw", "name": "Ludwig", "score": 90 }
]
}
}
Format B: Simple array (same for all platforms)
[
{ "id": "monstercat", "name": "Monstercat", "score": 100 },
{ "id": "sodapoppin", "name": "Sodapoppin", "score": 90 }
]
Format C: URLs only (auto-scores based on order)
{
"urls": "https://twitch.tv/monstercat https://twitch.tv/sodapoppin https://youtube.com/@ludwig"
}
| Field | Type | Description |
|---|---|---|
id |
string | Channel ID or username |
name |
string | Display name |
score |
number | Higher = higher priority (default: position-based) |
streams.json β Screen & Stream Sources{
"streams": [
{
"id": 1,
"screen": 1,
"enabled": true,
"width": 1920,
"height": 1080,
"x": 0,
"y": 0,
"volume": 70,
"quality": "best",
"window_maximized": true,
"primary": true,
"sources": [
{
"type": "holodex",
"subtype": "organization",
"enabled": true,
"priority": 10,
"limit": 20,
"name": "Hololive"
},
{
"type": "twitch",
"subtype": "favorites",
"enabled": true,
"priority": 20
},
{
"type": "youtube",
"subtype": "popular",
"enabled": true,
"priority": 30,
"limit": 10
}
],
"sorting": {
"field": "viewerCount",
"order": "desc",
"ignore": ["members_only"]
},
"refresh": 60,
"auto_start": true,
"skip_watched_streams": true
}
],
"organizations": ["Hololive", "Nijisanji", "VShojo"]
}
| Field | Type | Default | Description |
|---|---|---|---|
id |
number | required | Unique screen ID |
screen |
number | required | Display/monitor number |
enabled |
bool | true | Enable/disable this screen |
width |
number | 1280 | Window width |
height |
number | 720 | Window height |
x |
number | 0 | X position on desktop |
y |
number | 0 | Y position on desktop |
volume |
number (0-100) | 50 | Default volume |
quality |
string | "best" | Stream quality |
window_maximized |
bool | false | Start maximized |
primary |
bool | false | Primary screen |
sources |
array | [] | Stream sources (see below) |
sorting |
object | - | Sorting rules |
refresh |
number (sec) | 300 | Queue refresh interval |
auto_start |
bool | true | Auto-start on launch |
skip_watched_streams |
bool | true | Skip already watched |
| Type | Subtype | Description | Requires |
|---|---|---|---|
holodex |
organization |
Fetch by org name | name field |
holodex |
favorites |
Fetch favorite channels | favorites.json |
twitch |
favorites |
Fetch favorite Twitch channels | favorites.json |
twitch |
vtuber |
Fetch VTuber streams | - |
youtube |
favorites |
Fetch favorite YouTube channels | favorites.json |
youtube |
popular |
Fetch popular live streams | - |
| Field | Description |
|---|---|
viewerCount |
Sort by viewer count |
startTime |
Sort by start time (oldest first) |
priority |
Sort by priority number |
score |
Sort by favorite score |
player.json β Player Settings{
"prefer_streamlink": false,
"default_quality": "best",
"default_volume": 50,
"window_maximized": false,
"max_streams": 2,
"auto_start": true,
"disable_heartbeat": false,
"force_player": false,
"logging": {
"enabled": true,
"level": "info",
"max_size_mb": 50,
"max_files": 5
},
"screens": []
}
| Field | Type | Default | Description |
|---|---|---|---|
prefer_streamlink |
bool | false | Use Streamlink over MPV |
default_quality |
string | "best" | Default stream quality |
default_volume |
number (0-100) | 50 | Default volume |
window_maximized |
bool | false | Start maximized |
max_streams |
number | 4 | Max concurrent streams |
auto_start |
bool | true | Auto-start on launch |
disable_heartbeat |
bool | false | Disable health checks |
force_player |
bool | false | Keep player running |
logging |
object | - | Logging configuration |
mpv.json β MPV Player Configuration{
"priority": "normal",
"gpu-context": "auto",
"cache": "yes",
"cache-secs": 30,
"demuxer-max-bytes": 150M,
"demuxer-max-back-bytes": 50M
}
streamlink.json β Streamlink Configuration{
"path": "/usr/bin/streamlink",
"options": {
"player": "mpv",
"retry-open": 5,
"retry-streams": 10,
"hls-segment-threads": 5
},
"http_header": {
"User-Agent": "LiveLink/1.0"
}
}
filters.json β Stream Filters{
"filters": [
"members only",
"member only",
"membership",
"unavailable",
"private",
"deleted"
]
}
Filters out streams whose titles contain these keywords.
config.json β API Keys (Optional Fallback){
"holodex": { "api_key": "your-holodex-key" },
"twitch": {
"client_id": "your-twitch-client-id",
"client_secret": "your-twitch-client-secret"
},
"youtube": { "api_key": "your-youtube-key" }
}
Note: Environment variables override this file.
# List active streams
livelink stream list
livelink stream ls
# List with watch mode (refresh every 5s)
livelink stream list --watch
# Start stream
livelink stream start --url https://twitch.tv/xqc --screen 1 --quality best
# Stop stream
livelink stream stop 1
# Restart stream(s)
livelink stream restart --screen 1
livelink stream restart # all screens
# Refresh stream data
livelink stream refresh 1
livelink stream refresh # all screens
# Show queue
livelink queue show 1
livelink queue ls 1
# Add to queue
livelink queue add 1 https://twitch.tv/xqc "XQC Stream"
# Remove from queue (by index)
livelink queue remove 1 2
livelink queue rm 1 1,2,3 # batch remove
# Clear queue
livelink queue clear 1
# Watched streams
livelink queue watched
livelink queue mark-watched https://twitch.tv/xqc
livelink queue clear-watched
# List screens
livelink screen list
livelink screen ls
# Enable/disable screen
livelink screen enable 1
livelink screen disable 1
# Toggle screen
livelink screen toggle 1
# Pause/unpause
livelink player pause 1
livelink player pause all
# Set volume
livelink player volume 50 1
livelink player volume 50 all
# Seek
livelink player seek 30 1 # forward 30s
livelink player seek -10 1 # backward 10s
# Set process priority
livelink player priority high
# Start server
livelink start
# Stop server
livelink server stop
livelink server stop --all # stop players too
# Server status
livelink server status
# List organizations
livelink orgs
# Run diagnostics
livelink diagnostics
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLI / API β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ORCHESTRATOR β
β β’ Single authority for all stream operations β
β β’ Per-screen mutex locking β
β β’ State machine validation β
β β’ Max streams enforcement β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Holodex β β Twitch β β YouTube β
β Service β β Service β β Service β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Queue System β
β β’ Filter (watched, member) β
β β’ Sort (priority, viewers) β
βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Player Service β
β β’ MPV IPC control β
β β’ Health monitoring β
β β’ Crash recovery β
βββββββββββββββββββββββββββββββ
Idle ββstartβββΆ Starting ββsuccessβββΆ Playing
β² β β
β β error β stop
β βΌ βΌ
ββββββββββββββββ Error ββββββββββββββ Stopping
β
βΌ
Idle
cargo build
cargo build --release
cargo test
cargo test -- --nocapture # with output
cargo check
cargo clippy
cargo fmt
Log levels: error, warn, info, debug, trace
Set via environment:
export LOG_LEVEL=debug
cargo run
Log rotation is automatic (50MB, 5 files).
HOLODEX_API_KEY env var or config.json entryTWITCH_CLIENT_ID or TWITCH_CLIENT_SECRETmax_streams limit hit (default: 4)player.jsonCheck:
MIT
Built with: