-
Notifications
You must be signed in to change notification settings - Fork 0
Intermediate Guide
For Technicians - Configuration, Management, and Troubleshooting
- Architecture Overview
- Configuration System
- YAML File Structure
- Channel Management
- Schedule System
- Streaming System
- HDHomeRun Integration
- Advanced Troubleshooting
- Script Usage
StreamTV consists of several key components that work together:
┌─────────────────────────────────────────────────────────┐
│ Web Interface │
│ (HTML/JavaScript Frontend) │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ FastAPI Server │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ API │ │ IPTV │ │ HDHomeRun│ │
│ │ Routes │ │ Routes │ │ Routes │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ Business Logic Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Scheduling │ │ Streaming │ │ Importers │ │
│ │ Engine │ │ Manager │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ Data Layer │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Database │ │ File System │ │
│ │ (SQLite) │ │ (YAML/Logs) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
- Web Interface → API: User actions trigger API calls
- API → Business Logic: API routes call business logic functions
- Business Logic → Data: Logic reads/writes to database and files
- Streaming → External: Streams video from YouTube/Archive.org
- HDHomeRun → Plex: Emulates HDHomeRun device for Plex integration
Channel Creation Flow:
User uploads YAML → Import API → Channel Importer →
Parse YAML → Create Collections → Create Media Items →
Create Playlist → Create Channel → Database
Streaming Flow:
Client Request → IPTV Endpoint → Channel Manager →
Schedule Engine → Stream Manager → YouTube/Archive.org →
FFmpeg (MPEG-TS) → Client
Located in the project root, this file controls all StreamTV settings.
server:
host: "0.0.0.0" # Listen on all interfaces
port: 8410 # HTTP port
base_url: "http://localhost:8410" # Base URL for linksWhen to Change:
- Change
hostif you want to restrict access - Change
portif 8410 is already in use - Change
base_urlif accessing from another computer
database:
url: "sqlite:///./streamtv.db" # SQLite database fileWhen to Change:
- Use a different database file path
- Switch to PostgreSQL/MySQL (requires code changes)
streaming:
buffer_size: 8192 # Buffer size in bytes
chunk_size: 1024 # Chunk size for streaming
timeout: 30 # Timeout in seconds
max_retries: 3 # Retry attemptsWhen to Change:
- Increase
buffer_sizefor slower connections - Increase
timeoutfor slow sources - Increase
max_retriesfor unreliable sources
youtube:
enabled: true
quality: "best" # best, worst, or specific quality
extract_audio: false # Extract audio onlyWhen to Change:
- Set
qualityto "worst" for slower connections - Enable
extract_audiofor audio-only channels
archive_org:
enabled: true
preferred_format: "h264"
username: null # Your Archive.org username
password: null # Your Archive.org password
use_authentication: falseWhen to Change:
- Add credentials for restricted content
- Set
use_authentication: trueafter adding credentials
hdhomerun:
enabled: true
device_id: "FFFFFFFF" # Unique device ID
friendly_name: "StreamTV HDHomeRun"
tuner_count: 2 # Number of tuners
enable_ssdp: true # Enable discoveryWhen to Change:
- Change
device_idif you have multiple StreamTV instances - Increase
tuner_countfor more simultaneous streams - Set
enable_ssdp: falseif port 1900 is in use
ffmpeg:
ffmpeg_path: "/usr/local/bin/ffmpeg"
ffprobe_path: "/usr/local/bin/ffprobe"
log_level: "info" # error, warning, info, debug
threads: 0 # 0 = auto, or specific number
hwaccel: null # videotoolbox, vaapi, etc.
hwaccel_device: null # Device for hardware acceleration
extra_flags: null # Additional FFmpeg flagsWhen to Change:
- Set custom paths if FFmpeg is installed elsewhere
- Enable hardware acceleration for better performance
- Add
extra_flagsfor advanced FFmpeg options
Via Web Interface:
- Go to Settings → FFmpeg
- Edit values in the form
- Click Save
Via File:
- Edit
config.yamldirectly - Restart StreamTV for changes to take effect
Channel YAML files define complete channels with all their content.
channels:
- number: "1980"
name: "1980 Winter Olympics"
group: "Winter Olympics"
description: "Channel description"
enabled: true
streams:
- id: unique_id
collection: "Collection Name"
type: "event"
year: 1980
source: "youtube" # or "archive"
url: "https://www.youtube.com/watch?v=VIDEO_ID"
notes: "Optional notes"- number: Channel number (string, must be unique)
- name: Channel name
- enabled: true/false
- streams: List of media items
- id: Unique identifier for this stream
- collection: Collection name (groups related items)
- source: "youtube" or "archive"
- url: Full URL to the video
- type: Content type (event, news, commercial, etc.)
- year: Year of content
- runtime: Duration in ISO 8601 format (PT3M44S = 3 minutes 44 seconds)
- notes: Optional description
channels:
- number: "1980"
name: "1980 Winter Olympics"
group: "Winter Olympics"
enabled: true
streams:
- id: opening_ceremony
collection: "1980 Opening Ceremony"
type: "event"
year: 1980
source: "youtube"
url: "https://www.youtube.com/watch?v=uTW6jH3sk1k"
runtime: "PT3M44S"
notes: "Opening ceremony teaser"Schedule files define how content plays on a channel (ErsatzTV-style).
name: "Channel Name"
description: "Channel description"
content:
- key: content_key
collection: "Collection Name"
order: chronological # or shuffle
sequence:
- name: "Main Sequence"
items:
- collection: "Collection Name"
- duration: "00:30:00" # Fill 30 minutes
collection: "Filler Collection"
- all: "Collection Name" # Play all items
playout:
- name: "Main Playout"
sequence: "Main Sequence"
repeat: trueDefines available content collections:
content:
- key: main_content
collection: "Main Show Collection"
order: chronological
- key: commercials
collection: "Commercial Collection"
order: shuffle # Randomize orderDefines playback sequences:
sequence:
- name: "Prime Time"
items:
# Play a collection
- collection: "main_content"
# Fill duration with filler
- duration: "00:05:00"
collection: "commercials"
# Play all items in collection
- all: "main_content"
# Pre-roll (before main content)
- pre_roll: true
collection: "station_ids"
# Mid-roll (during content)
- mid_roll: true
collection: "commercials"
# Post-roll (after content)
- post_roll: true
collection: "sign_offs"Defines how sequences are used:
playout:
- name: "24/7 Stream"
sequence: "Prime Time"
repeat: true # Loop continuouslyDuration-based Filler:
- duration: "00:30:00" # Fill exactly 30 minutes
collection: "Filler Collection"
discard_attempts: 5 # Skip items that don't fitTime-based Scheduling:
- padToNext: "00:00:00" # Pad to next hour
collection: "Filler"
- padUntil: "12:00:00" # Pad until noon
collection: "Filler"
- waitUntil: "20:00:00" # Wait until 8 PM
collection: "Prime Time"- Create a channel YAML file (see structure above)
- Go to Import in web interface
- Upload or drag the YAML file
- Click Import
curl -X POST http://localhost:8410/api/channels \
-H "Content-Type: application/json" \
-d '{
"number": "1980",
"name": "1980 Winter Olympics",
"group": "Winter Olympics",
"enabled": true
}'python3 scripts/create_channel.py --number 1980 --name "1980 Olympics"- Web Interface: Toggle switch in Channels page
-
API:
PUT /api/channels/{channel_id}with{"enabled": true/false}
- Web Interface: Click Edit on channel
-
API:
PUT /api/channels/{channel_id}
- Web Interface: Click Delete (with confirmation)
-
API:
DELETE /api/channels/{channel_id}
Enabled: Channel is active and streaming Disabled: Channel exists but is not streaming No Content: Channel has no playlists or schedules
- Content Definition: Define what content is available
- Sequence Definition: Define playback order and logic
- Playout Definition: Define how sequences are used
- Timeline Calculation: System calculates current position based on midnight start
Schedule files are in the schedules/ directory:
- Format:
mn-olympics-{year}.yml - Or:
{channel-name}.yml
The Schedule Engine:
- Parses schedule YAML files
- Generates playlists from sequences
- Handles repeats and loops
- Calculates timeline positions
Midnight Start: All channels start at midnight (00:00:00) of their creation day System Time Sync: Uses server system time to calculate current position Continuous Playback: Streams continuously, clients join at current position
Schedule files are validated against JSON schema:
- Location:
schemas/schedule.schema.json - Validates structure and data types
- Web interface shows validation errors
- Direct streaming via
yt-dlp - No downloads required
- Supports all YouTube formats
- Handles geo-restrictions
- Direct streaming from Archive.org
- Supports authentication for restricted content
- Multiple format support
The Stream Manager:
- Detects source type from URL
- Routes to appropriate adapter
- Handles errors and retries
- Manages stream URLs
For HDHomeRun/Plex compatibility:
- Transcodes to MPEG-TS format
- Uses FFmpeg for transcoding
- Continuous streaming (no gaps)
- Hardware acceleration support
Manages continuous streams:
- Starts all channels on server startup
- Maintains timeline for each channel
- Broadcasts to multiple clients
- Handles client connections/disconnections
StreamTV emulates an HDHomeRun device:
- SSDP Discovery: Broadcasts on network (port 1900)
-
Discovery Endpoint:
/hdhomerun/discover.json -
Lineup Endpoint:
/hdhomerun/lineup.json -
Stream Endpoint:
/hdhomerun/auto/v{channel_number}
-
Add Tuner:
- Plex → Settings → Live TV & DVR
- Add Tuner → HDHomeRun
- Enter:
http://YOUR_IP:8410/hdhomerun/discover.json
-
Add Guide:
- Use XMLTV URL:
http://YOUR_IP:8410/iptv/xmltv.xml
- Use XMLTV URL:
-
Map Channels:
- Plex will detect channels
- Map to guide data
Plex Can't Find Tuner:
- Check SSDP is enabled
- Check firewall allows port 1900
- Try manual discovery URL
Channels Not Appearing:
- Check channels are enabled
- Check XMLTV guide is generating
- Verify channel numbers match
Stream Won't Play:
- Check FFmpeg is installed
- Check FFmpeg path in config
- Check logs for FFmpeg errors
Location: streamtv.log (or configured path)
Log Levels:
- ERROR: Critical errors
- WARNING: Potential issues
- INFO: General information
- DEBUG: Detailed debugging
View Logs:
tail -f streamtv.logCause: Timeline not initialized correctly
Solution:
- Check channel
created_atin database - Verify midnight calculation
- Check system time is correct
- Restart StreamTV
Cause: Schedule not looping
Solution:
- Check schedule has
repeat: true - Verify sequence is complete
- Check for errors in logs
Cause: FFmpeg configuration or missing codecs
Solution:
- Verify FFmpeg installation:
ffmpeg -version - Check FFmpeg path in config
- Test FFmpeg command manually
- Check hardware acceleration settings
Cause: YAML has placeholder URLs
Solution:
- Run cleanup script:
python3 scripts/cleanup_placeholders.py --execute - Update YAML files with real URLs
- Re-import channels
Check Database:
sqlite3 streamtv.db ".tables"
sqlite3 streamtv.db "SELECT * FROM channels;"Backup Database:
cp streamtv.db streamtv.db.backupReset Database (WARNING: Deletes all data):
rm streamtv.db
# Restart StreamTV to recreatepython3 scripts/import_channels.py path/to/channel.ymlOptions:
- Validates YAML before import
- Creates collections and media items
- Creates playlists
- Creates or updates channel
python3 scripts/cleanup_placeholders.py [--execute]Options:
-
--execute: Actually delete (default is dry-run) - Finds all placeholder URLs
- Removes from database
python3 scripts/create_channel.py \
--number 1980 \
--name "1980 Olympics" \
--group "Winter Olympics"Options:
-
--number: Channel number (required) -
--name: Channel name (required) -
--group: Channel group (optional) -
--enabled: Enable channel (default: true)
- Ready for Deep Dive? → Read the Expert Guide
- Need Troubleshooting Help? → Use Troubleshooting Scripts
- Want API Details? → Read API Documentation
Last Updated: 2025-01-28