A high-performance Go-based IPTV proxy server that intelligently aggregates streams from multiple sources, provides automatic channel deduplication, failover capabilities, and serves them through a unified M3U8 playlist with advanced streaming options including FFmpeg integration.
- Secure Admin Interface: Full authentication system protecting the admin panel
- Argon2id Password Hashing: Industry-leading memory-hard password hashing
- Session Management: HTTP-only secure cookies with configurable TTL (24h default, 30-day remember me)
- API Token System: Multiple named API tokens with granular permission control
- First-Run Registration: On fresh install, guided admin account creation before access is granted
- Local Network Restriction: HDHomeRun emulation endpoints restricted to RFC1918 addresses only
- XC Account Authentication: All M3U and stream output endpoints authenticated via Xtream Codes accounts
Tokens support granular permission bitmasks:
| Permission | Description |
|---|---|
Read |
GET endpoints only |
Config Write |
Modify global configuration |
Restart |
Trigger graceful restarts |
Streams |
Manage channels and streams |
Logs |
Read and clear logs |
XC Accounts |
Manage Xtream Codes output accounts |
EPGs |
Manage EPG sources |
Schedules Direct |
Manage Schedules Direct accounts |
- Combines multiple IPTV sources into a single unified playlist
- Intelligent channel grouping by name (deduplicates channels across sources)
- Automatic source prioritization and failover
- Per-source connection limits to prevent provider overload
- Master Playlist Detection: Automatically detects and processes HLS master playlists
- Variant Selection: Intelligently selects optimal stream variants (highest quality with fallback)
- Channel Deduplication: Groups identical channels from different sources
- Smart Failover: Seamlessly switches between sources when streams fail
- Ad-Insertion Handling: Automatically resolves tracking URLs and beacon redirects
- Stream Validation: Uses ffprobe to validate stream quality before serving
- Go Restreaming Mode: Single upstream connection shared among multiple clients
- FFmpeg Proxy Mode: Hardware-accelerated streaming with advanced codec support
- Provider-Friendly: Reduces load on upstream providers and prevents rate limiting
- Automatic Management: Intelligent connection pooling and cleanup of inactive streams
- Scalable: Supports unlimited clients per channel with minimal resource overhead
- Tracking URL Resolution: Automatically extracts real video URLs from ad-insertion systems
- Beacon URL Handling: Supports complex ad systems like AccuWeather's tracking URLs
- Format Error Recovery: Handles streams with format quirks (like BBC America)
- Segment Validation: Smart validation that skips problematic tracking URLs
- Multi-Variant Testing: Tests all available quality variants automatically
- Worker pool-based parallel processing
- Ring buffer streaming with configurable sizes
- Built-in caching for playlists and metadata
- Rate limiting and connection management
- Comprehensive retry logic with exponential backoff
- Stream health monitoring and automatic blocking of failed sources
- SQLite-based configuration with per-source customization
- Per-source settings for headers, timeouts, retries, and connection limits
- Flexible source configuration with custom User-Agent, Origin, and Referrer headers
- Customizable stream sorting by any M3U8 attribute
- URL obfuscation for privacy and security
- Configurable timeouts and buffer sizes
- Debug mode with extensive logging
- FFmpeg integration with custom pre-input and pre-output arguments
- Prometheus metrics integration
- Connection tracking per channel and source
- Stream error monitoring and categorization
- Health check endpoints
- Detailed logging with configurable verbosity
- Dark Mobile-Friendly Design: Responsive web interface optimized for all devices
- Custom CSS Support: Load custom styles from
/settings/custom.cssfor personalized theming - Real-Time Dashboard: Live statistics, active channels, and system monitoring
- Configuration Management: Edit global settings and per-source configurations through web UI
- Source Management: Add, edit, delete, and reorder IPTV sources with full validation
- Channel Monitoring: View all channels with real-time status and client information
- Live Logs: Real-time log viewing with filtering by level (error, warning, info, debug)
- Graceful Restart: Apply configuration changes with zero-downtime restarts
- Auto-Refresh: Dashboard updates every 5 seconds for real-time monitoring
- Security Tab: Manage API tokens with granular permissions directly from the UI
- Stream Health Tracking: Mark problematic streams as "dead" to prevent automatic selection
- Manual Stream Control: Activate specific streams or mark them as unplayable through the admin interface
- Stream Revival: Restore previously dead streams when they become functional again
- Persistent Dead Stream Storage: Dead stream information stored in SQLite
- Intelligent Stream Selection: Proxy automatically skips dead streams during failover
- Visual Dead Stream Indicators: Clear visual markers for dead streams in the admin interface
- Real-Time Health Monitoring: Continuously monitors active streams for playback issues
- Intelligent Failover: Automatically switches to backup streams when problems are detected
- State-Based Detection: Monitors buffer health, activity timestamps, and connection status
- No Additional Network Load: Uses existing connection state without extra requests
- Provider-Friendly: Respects existing connection limits and reuses established connections
- Configurable Timing: Adjustable monitoring intervals (default: 30 seconds, 5 consecutive failures)
- Seamless Switching: Automatic failover maintains client connections during stream transitions
- Integration with Existing Logic: Leverages all existing stream management and failover mechanisms
- Hardware Acceleration: Support for GPU-accelerated encoding/decoding via host device passthrough
- Advanced Codec Support: Handle complex video formats and containers
- Custom Arguments: Configurable pre-input and pre-output FFmpeg arguments
- Automatic Detection: Intelligent stream format detection and processing
- Resource Optimization: Efficient memory usage and CPU optimization
- Format Conversion: Real-time transcoding and format adaptation
- Ad-Break Handling: Properly manages MPEG-TS discontinuities from ad-insertion systems
- XC-Compatible API: Expose your aggregated streams via a full Xtream Codes compatible API
- Multi-Account Support: Create multiple XC output accounts with independent credentials
- Per-Account Content Control: Enable or disable Live, VOD, and Series per account
- Connection Limits: Configurable maximum connections per account
- M3U Playlist Export: Path-based M3U playlist URLs with per-account content filtering
- XMLTV EPG: Full EPG passthrough
- Quick Copy: Copy base URL, username, password, and playlist URLs directly from the admin interface
- Local Source Scanning: Index local movie, TV show, and music libraries directly into the proxy's VOD/series catalog
- Emby/Jellyfin/Plex-Compatible Layout: Reads standard folder structures — series/season folders, NFO sidecars, poster/fanart artwork
- NFO & Embedded Tag Enrichment: Parses
.nfometadata and embedded audio tags, with ffprobe fallback when available - Manual Scanning: Scan a single source or all sources on demand from the admin interface — no cron integration
- Metadata Editing: Edit title, plot, cast, genres, and artwork associations from the admin UI; writes changes back to
.nfosidecars (and embedded tags for music) - Direct File Serving: Local files stream straight from disk with range request support, not proxied through the aggregation pipeline
- XC Catalog Integration: Local movies and shows are appended to Xtream Codes VOD/series output; music rides in VOD under categories
- Proxied Logos: Live channel logos are fetched once, cached on disk under
/settings/logos/cache, and served from the proxy — exports never point at a provider CDN - Resolution Order: Manual override → uploaded logo → mapped EPG
<icon>→ providertvg-logo→ configured default - Uploads & Library: Upload a logo per channel or pick one already uploaded; files are content-hashed under
/settings/logos - Bulk EPG Pull: Assign mapped EPG icons across every mapped channel in one pass
- Lazy & Warmed: Uncached logos fetch on first request, and every import commit warms the live channel set in the background
- Cache TTL: Cached logos expire on the global cache duration; a stale copy is preferred over a failed fetch
A special thank you to the contributors who help improve this project!
|
Azq2 |
💡 Added a mechanism to preserve the original provider sort order. |
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ IPTV Source 1 │ │ IPTV Source 2 │ │ IPTV Source N │
│ (5 max conns) │ │ (10 max conns) │ │ (3 max conns) │
│ Custom Headers │ │ Custom Headers │ │ Custom Headers │
└─────────┬───────┘ └─────────┬────────┘ └─────────┬───────┘
│ │ │
└──────────────────────┼───────────────────────┘
│
┌────────────▼────────────┐
│ KPTV Proxy │
│ • Auth (Argon2id) │
│ • API Token Auth │
│ • Channel grouping │
│ • Master playlist │
│ detection │
│ • Tracking URL │
│ resolution │
│ • Per-source config │
│ • Failover logic │
│ • Connection mgmt │
│ • Web Admin Interface │
│ • Dead Stream Mgmt │
│ • Stream Watcher │
│ • FFmpeg Integration │
│ • XC Output API │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ Unified M3U + XC │
│ /pl/{user}/{pass} │
│ /player_api.php │
└─────────────────────────┘
│
┌──────────────────────┼──────────────────────┐
│ │ │
┌─────────▼───────┐ ┌─────────▼───────┐ ┌─────────▼───────┐
│ Client 1 │ │ Client 2 │ │ Client N │
│ (VLC, Kodi, │ │ (Smart TV, │ │ (Mobile App, │
│ etc.) │ │ etc.) │ │ etc.) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Prerequisites: Docker or Podman installed
- Create settings directory:
mkdir settings- Start the proxy:
# Docker
docker compose up -d
# Or Podman
podman-compose up -d- Complete initial setup:
On first run, navigate to http://your-server-ip:PORT/ — you will be redirected to /register to create your admin account.
- Access your services:
Admin Interface: http://your-server-ip:PORT/
Login: http://your-server-ip:PORT/login
Unified Playlist: http://your-server-ip:PORT/pl/{username}/{password}
Group Filtered Playlist: http://your-server-ip:PORT/pl/{username}/{password}/{group}
XC API: http://your-server-ip:PORT/player_api.php
Note:
{group}must match a channel'sgroup-title. For XC sources this is the provider's own category name (e.g.USA | ENTERTAINMENT), not the content type —live,vod, andseriesare no longer valid group filters for XC-sourced channels unless a provider happens to name a category that.
services:
kptv-proxy:
image: ghcr.io/kpirnie/kptv-proxy:latest
container_name: kptv_proxy
restart: unless-stopped
ports:
- WHATEVER_PORT_YOU_WANT_TO_USE:8080
volumes:
- ./settings/:/settings/
# To utilize FFmpeg, install it on your host and mount the binaries:
#- /usr/local/bin/ffmpeg:/usr/local/bin/ffmpeg:ro
#- /usr/local/bin/ffprobe:/usr/local/bin/ffprobe:ro
healthcheck:
test: [ "CMD", "curl", "-v", "http://127.0.0.1:8080/api/stats" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 30sFor hardware-accelerated transcoding, FFmpeg reads and decodes using your GPU via VAAPI. This requires:
- FFmpeg and FFprobe installed on the host machine
- The host's DRI render node passed through to the container (
/dev/dri) - The host's VA-API driver libraries mounted into the container
- The container user added to the
videoandrendergroups
services:
kptv-proxy:
image: ghcr.io/kpirnie/kptv-proxy:latest
container_name: kptv_proxy
restart: unless-stopped
ports:
- WHATEVER_PORT_YOU_WANT_TO_USE:8080
volumes:
- ./settings/:/settings/
- /usr/local/bin/ffmpeg:/usr/local/bin/ffmpeg:ro
- /usr/local/bin/ffprobe:/usr/local/bin/ffprobe:ro
- /usr/lib/x86_64-linux-gnu/dri:/usr/lib/x86_64-linux-gnu/dri:ro
devices:
- /dev/dri:/dev/dri
group_add:
- video
- render
healthcheck:
test: [ "CMD", "curl", "-v", "http://127.0.0.1:8080/api/stats" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 30sOn first run with no existing admin account, navigating to the admin interface automatically redirects to /register where you create your admin account with full name, email, username, and password (minimum 8 characters, hashed with Argon2id).
Authenticate with either your username or email address plus password at /login. Optionally check Remember me to extend your session to 30 days.
API tokens allow programmatic access to the admin API without session cookies. Create tokens from the Accounts tab with specific permissions:
- Tokens are 64 characters of cryptographically secure random alphanumeric characters
- The raw token is shown exactly once at creation — copy it immediately
- Tokens are stored as Argon2id hashes — the raw value is never stored
- Each token has a friendly name and a permission bitmask
- Tokens can be deleted (revoked) at any time
Use tokens via the Authorization header:
curl -H "Authorization: Bearer YOUR_TOKEN" http://your-server:PORT/api/statsFrom the Accounts tab in the admin interface, use the change password form. Requires your current password.
Access the admin interface at http://your-server:port/ after logging in.
Create /settings/custom.css to customize the admin interface appearance. This file is automatically loaded.
Base Framework: TailWindCSS. See: https://tailwindcss.com/docs/styling-with-utility-classes
- Real-Time Statistics: Total channels, active streams, connected clients, memory usage
- System Status: Server uptime, cache status, worker thread count, FFmpeg mode
- Traffic Metrics: Connection counts, bytes transferred, stream errors
- Active Channels: Live view of currently streaming channels with client counts, codec info, resolution, and bitrate badges
- Auto-Refresh: Updates every 5 seconds
- Edit all configuration parameters through intuitive web forms
- FFmpeg mode toggle and argument configuration
- Validation and error handling for all settings
- Save changes and trigger graceful restart to apply new configuration
The Accounts tab consolidates all output account management and security:
Xtream Codes Output Accounts — Create XC-compatible output accounts to expose your aggregated streams to any Xtream Codes compatible player (Tivimate, IPTV Smarters, etc.).
Per-account configuration:
| Setting | Description |
|---|---|
| Name | Friendly name for the account |
| Username | XC login username |
| Password | XC login password (auto-generate available) |
| Max Connections | Maximum simultaneous streams for this account |
| Enable Live | Include live TV streams |
| Enable Series | Include series content |
| Enable VOD | Include video on demand |
Note: Enable Live/Series/VOD control what appears in the account's generated M3U playlist and XC catalog listings only. Direct stream routes (
/live/,/movie/,/series/) authenticate on the account's username/password alone and aren't gated by these flags.
Quick copy buttons on each account card:
- Base URL
- Username
- Password
- All M3U playlist URL
- Live M3U playlist URL
- Series M3U playlist URL
- VOD M3U playlist URL
API Tokens — Create and manage API tokens for programmatic access with granular permissions.
- Add/Edit Sources: Full configuration interface for IPTV sources
- Per-Source Settings: Custom timeouts, retry logic, connection limits
- Custom Headers: Configure User-Agent, Origin, Referrer per source
- Content Filtering: Per-source regex filters for Live, VOD, and Series content
- Priority Management: Reorder sources by priority for failover
- XC API Sources: Set username and password for Xtream Codes API sources
Managed as a sub-tab under Source Management, alongside Remote Sources.
- Add/Edit Local Sources: Configure a filesystem path, media type (Music, Movies, or Shows), and group prefix
- Include/Exclude Filtering: Per-source regex filters for what gets scanned
- Manual Scan: Scan an individual source or all enabled sources on demand
- Scan Status: Last scan time and entry count shown per source
- All Channels View: Complete list of available channels with status
- Stream Selection: Choose specific streams for each channel with activate/kill controls
- Dead Stream Management: Mark streams as dead or revive them with visual indicators
- Real-Time Status: Active/inactive indicators with client counts
- Search & Filter: Find channels by name or group
- Logo Management: Set a channel logo by URL, upload, library pick, or EPG pull, with a bulk EPG pull across mapped channels
- Auto-Refresh: Live updates of channel status
- Local Media Browser: Search and filter scanned local entries by source and free-text query
- Metadata Editing: Edit title, plot, tagline, cast, genres, studios, ratings, and identifiers (IMDB/TMDB/TVDB) per entry
- Artwork Preview: View poster and fanart associated with each entry
- Writes Back to Disk: Saved edits update the
.nfosidecar (and embedded tags for music) and re-scan the file
- Real-Time Viewing: Live log stream with auto-scrolling
- Level Filtering: Filter by error, warning, info, debug levels
- Search Functionality: Find specific log entries
- Clear Logs: Remove old entries to maintain performance
KPTV Proxy supports two streaming modes. In order to utilize FFmpeg, you must have it installed on your host machine and mount the binaries into the container.
- Pure Go implementation
- Efficient memory usage
- Fast startup times
- Basic stream processing
- Hardware acceleration support via host GPU passthrough
- Advanced codec handling
- Handles MPEG-TS discontinuities (ad breaks, stream transitions)
- Comprehensive format support
Simple copy mode (no GPU):
{
"ffmpegMode": true,
"ffmpegPreInput": [],
"ffmpegPreOutput": ["-c", "copy", "-f", "mpegts"]
}Common FFmpeg Arguments:
Pre-Input:
"-re"- Read input at native frame rate"-rtsp_transport", "tcp"- Use TCP for RTSP"-fflags", "nobuffer"- Disable input buffering"-hwaccel", "vaapi"- Enable VAAPI hardware acceleration"-hwaccel_device", "/dev/dri/renderD128"- Specify render device
Pre-Output:
"-c", "copy"- Copy streams without re-encoding"-c:v", "h264_vaapi"- H.264 encoding via VAAPI"-c:a", "aac"- AAC audio encoding"-f", "mpegts"- MPEG-TS output format"-mpegts_flags", "initial_discontinuity"- Handle ad-break discontinuities
- Manual Stream Control: Mark streams as dead or revive them from the admin interface
- Automatic Blocking: Streams exceeding failure thresholds are auto-blocked
- Persistent Storage: Dead stream data stored in SQLite
- Automatic Skipping: Proxy skips dead streams during failover
- Stream Revival: Dead streams can be restored when functional again
- In the admin interface, navigate to any channel and click Streams
- Each stream shows:
▶️ Activate: Switch to this specific stream- 🚫 Kill: Mark this stream as dead
- 🔄 Revive: Restore a dead stream
- During automatic failover, dead streams are skipped
The Stream Watcher runs as a background service monitoring active streams every 30 seconds (15 seconds in debug mode).
Monitored Conditions:
- Buffer Throughput: Detects streams delivering less than 200KB per check interval
- Stream Activity: Monitors data flow timestamps (120 second inactivity threshold)
- Context Status: Detects stuck or cancelled stream contexts
- FFprobe Stats: Monitors stream stats staleness (10 minute threshold)
Automatic Actions:
- Consecutive Failure Tracking: Requires 3 total failures before switching
- Intelligent Failover: Automatically switches to next available healthy stream
- Seamless Transition: Maintains client connections during stream changes
- Self-Recovery: Clears failure counters when stream recovers without intervention
| Endpoint | Description |
|---|---|
GET / |
Web admin interface (requires admin auth) |
GET /login |
Login page |
GET /register |
Initial setup page (only accessible when no admin exists) |
GET /logout |
Logout and clear session |
GET /metrics |
Prometheus metrics (requires admin auth) |
GET /pl/{username}/{password} |
Unified playlist (XC account auth) |
GET /pl/{username}/{password}/{group} |
Group-filtered playlist (XC account auth) |
GET /s/{username}/{password}/{channel} |
Stream proxy with automatic failover (XC account auth) |
GET /epg/{username}/{password} |
EPG (XC account auth) |
GET /epg.xml/{username}/{password} |
EPG XML (XC account auth) |
GET /local/{username}/{password}/{hash} |
Local media file stream, range requests supported (XC account auth) |
GET /localart/{username}/{password}/{hash}/{kind} |
Local media artwork — poster or fanart (XC account auth) |
All /api/* endpoints require either a valid session cookie or a Authorization: Bearer TOKEN header with appropriate permissions.
| Endpoint | Method | Description |
|---|---|---|
/api/auth/me |
GET | Current session info |
/api/auth/password |
POST | Change password |
/api/auth/permissions |
GET | Permission constants |
/api/auth/tokens |
GET | List API tokens |
/api/auth/tokens |
POST | Create API token |
/api/auth/tokens |
DELETE | Delete API token |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/config |
GET | Read | Get current configuration |
/api/config |
POST | Config Write | Update configuration |
/api/stats |
GET | Read | System statistics |
/api/restart |
POST | Restart | Graceful restart |
/api/watcher/toggle |
POST | Streams | Enable/disable stream watcher |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/channels |
GET | Read | All channels |
/api/channels/active |
GET | Read | Active channels only |
/api/channels/{channel}/streams |
GET | Read | Available streams for channel |
/api/channels/{channel}/stats |
GET | Read | Stream stats for channel |
/api/channels/{channel}/stream |
POST | Streams | Set active stream |
/api/channels/{channel}/kill-stream |
POST | Streams | Mark stream as dead |
/api/channels/{channel}/revive-stream |
POST | Streams | Revive dead stream |
/api/channels/{channel}/order |
POST | Streams | Set stream order |
/api/channels/{channel}/order |
DELETE | Streams | Reset channel to default stream order |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/logs |
GET | Logs | Application logs |
/api/logs |
DELETE | Logs | Clear logs |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/xc-accounts |
GET | XC Accounts | List XC output accounts |
/api/xc-accounts |
POST | XC Accounts | Create XC output account |
/api/xc-accounts/{id} |
PUT | XC Accounts | Update XC output account |
/api/xc-accounts/{id} |
DELETE | XC Accounts | Delete XC output account |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/epgs |
GET | EPGs | List EPG sources |
/api/epgs |
POST | EPGs | Create EPG source |
/api/epgs/{id} |
PUT | EPGs | Update EPG source |
/api/epgs/{id} |
DELETE | EPGs | Delete EPG source |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/channels/{channel}/epg |
GET | Read | Get EPG mapping for a channel |
/api/channels/{channel}/epg |
POST | EPGs | Set EPG mapping for a channel |
/api/channels/{channel}/epg |
DELETE | EPGs | Clear EPG mapping for a channel |
/api/epg/search |
GET | Read | Fuzzy search the EPG channel index (?q=) |
/api/channels/epg-mappings |
GET | Read | All channel → EPG ID mappings |
/api/epgs/refresh |
POST | EPGs | Trigger an immediate EPG cache refresh |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/local-sources |
GET | Read | List configured local media sources |
/api/local-sources |
POST | Config Write | Create a local media source |
/api/local-sources/{id} |
PUT | Config Write | Update a local media source |
/api/local-sources/{id} |
DELETE | Config Write | Delete a local media source |
/api/local-sources/{id}/scan |
POST | Config Write | Scan a single local source |
/api/local-sources/scan |
POST | Config Write | Scan all enabled local sources |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/local-media |
GET | Read | List scanned local media entries (?source=, ?q=, ?page=, ?size=) |
/api/local-media/{hash} |
GET | Read | Get a single local media entry |
/api/local-media/{hash} |
PUT | Config Write | Edit metadata for a local media entry |
/api/local-media/{hash}/art/{kind} |
GET | Read | Get poster or fanart for a local media entry (kind: poster or fanart) |
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/sd-accounts |
GET | SD | List SD accounts |
/api/sd-accounts |
POST | SD | Create SD account |
/api/sd-accounts/{id} |
PUT | SD | Update SD account |
/api/sd-accounts/{id} |
DELETE | SD | Delete SD account |
/api/sd/discover |
POST | SD | Discover SD lineups |
| Endpoint | Description |
|---|---|
GET /player_api.php |
Main XC API endpoint |
GET /get.php |
M3U playlist export |
GET /xmltv.php |
EPG data |
GET /live/{user}/{pass}/{id} |
Live stream. A request for {id}.m3u8 gets a 307 redirect to the canonical {id}.ts URL rather than being served directly. |
GET /movie/{user}/{pass}/{id} |
VOD stream. The file extension reflects the source's actual container (e.g. .mp4, .mkv), not always .ts. |
GET /series/{user}/{pass}/{id} |
Series stream. Same real-container-extension behavior as VOD. |
| Endpoint | Description |
|---|---|
GET /discover.json |
Device discovery |
GET /device.xml |
UPnP device descriptor |
GET /lineup_status.json |
Lineup status |
GET /lineup.json |
Channel lineup |
Note: HDHomeRun endpoints are restricted to RFC1918 (local network) addresses only. Requests from public IPs will receive a 403 Forbidden response. If behind a reverse proxy, set
X-Forwarded-Forappropriately.
Each stream is classified as live, vod, or series so filters, XC catalog placement, and account content toggles apply correctly.
- XC sources: content type comes directly from which XC API endpoint the entry was fetched from (
get_live_streams,get_vod_streams,get_series) — not guessed. A live entry whose name contains24/7is still reclassified as series, matching the pattern used for M3U sources. - M3U sources: content type is inferred from the stream name, URL, and
group-title/tvg-groupattributes, in that order. - group-title on XC sources: reflects the provider's own category name for that stream, not the literal content type. A category with no usable name falls back to
live,vod, orseries.
| Setting | Default | Description |
|---|---|---|
baseURL |
"http://localhost:8080" |
Base URL for generated stream links |
bufferSizePerStream |
16 |
Per-stream buffer size in MB |
cacheEnabled |
true |
Enable playlist caching |
cacheDuration |
"30m" |
Cache lifetime |
importRefreshInterval |
"12h" |
How often to refresh source playlists |
workerThreads |
4 |
Parallel workers for import processing |
debug |
false |
Enable verbose logging |
obfuscateUrls |
true |
Hide source URLs in logs |
sortField |
"tvg-name" |
Sort streams by attribute; use "preserve-order" to keep source playlist/API order |
sortDirection |
"asc" |
Sort direction: asc or desc |
streamTimeout |
"10s" |
Global timeout for stream validation |
maxConnectionsToApp |
100 |
Maximum total connections to the application |
watcherEnabled |
true |
Enable automatic stream monitoring |
ffmpegMode |
false |
Use FFmpeg instead of Go streaming |
ffmpegPreInput |
[] |
FFmpeg arguments before -i |
ffmpegPreOutput |
[] |
FFmpeg arguments before output |
responseHeaderTimeout |
"10s" |
Timeout for response headers from source |
| Setting | Required | Description | Example |
|---|---|---|---|
name |
Yes | Friendly name | "Primary IPTV" |
url |
Yes | M3U8 playlist URL or XC base URL | "http://provider.com/list.m3u8" |
username |
No | XC API username | "user123" |
password |
No | XC API password | "pass456" |
order |
No | Priority order (lower = higher priority) | 1 |
maxConnections |
No | Max concurrent connections | 5 |
maxStreamTimeout |
No | Timeout for streams | "30s" |
retryDelay |
No | Delay between retries | "5s" |
maxRetries |
No | Retry attempts per failure | 3 |
maxFailuresBeforeBlock |
No | Failures before blocking | 5 |
minDataSize |
No | Minimum data size in KB | 2 |
userAgent |
No | Custom User-Agent header | "VLC/3.0.18" |
reqOrigin |
No | Custom Origin header | "https://provider.com" |
reqReferrer |
No | Custom Referrer header | "https://provider.com/player" |
liveIncludeRegex |
No | Only include live streams matching pattern | ".*USA.*" |
liveExcludeRegex |
No | Exclude live streams matching pattern | ".*adult.*" |
seriesIncludeRegex |
No | Only include series matching pattern | "" |
seriesExcludeRegex |
No | Exclude series matching pattern | "" |
vodIncludeRegex |
No | Only include VOD matching pattern | "" |
vodExcludeRegex |
No | Exclude VOD matching pattern | "" |
For XC sources, the importer fetches live, series, and VOD catalogs plus each type's category list. group-title is set from the provider's category name where available, falling back to the content type name. The live/series/VOD include and exclude regexes are applied after the full catalog is fetched, so changing a filter takes effect on the next import without a re-fetch of the provider's data. Editing a source's filters also invalidates any previously compiled filter for that source immediately, rather than waiting for a restart.
| Setting | Required | Description |
|---|---|---|
name |
Yes | Friendly account name |
username |
Yes | XC login username |
password |
Yes | XC login password |
maxConnections |
No | Max simultaneous streams (default: 10) |
enableLive |
No | Include live streams (default: true) |
enableSeries |
No | Include series (default: false) |
enableVOD |
No | Include VOD (default: false) |
# Check container health
docker-compose ps
# View real-time logs
docker-compose logs -f kptv-proxy
# Check FFmpeg mode status
docker-compose logs kptv-proxy | grep FFMPEG
# Monitor stream watcher activity
docker-compose logs kptv-proxy | grep WATCHERiptv_proxy_active_connections- Active connections per channeliptv_proxy_bytes_transferred- Data transfer metricsiptv_proxy_stream_errors- Error counts by typeiptv_proxy_clients_connected- Connected clients per channeliptv_proxy_stream_switches_total- Stream switch events
Problem: Can't access admin interface
- ✅ On first run, navigate to
/registerto create your admin account - ✅ If you have an account, navigate to
/login - ✅ Check that cookies are enabled in your browser
Problem: API token not working
- ✅ Ensure the
Authorization: Bearer TOKENheader is set correctly - ✅ Verify the token has the required permission for the endpoint
- ✅ Token is shown only once at creation — regenerate if lost by deleting and creating a new one
Problem: Configuration not loading
- ✅ Use the web admin interface to edit configuration
- ✅ Check logs in admin interface or container logs
Problem: FFmpeg not working
- ✅ Verify FFmpeg is installed on your host:
$(which ffmpeg) -version - ✅ Verify both
ffmpegandffprobebinaries are mounted into the container - ✅ Check FFmpeg arguments in debug logs
- ✅ Test with simple arguments first:
["-c", "copy"] - ✅ For hardware acceleration, verify
/dev/dridevice passthrough and driver library mount
Problem: Hardware acceleration not working
- ✅ Verify render node exists:
ls /dev/dri/on host - ✅ Confirm correct render node in config (usually
renderD128) - ✅ Verify VA-API driver library path for your distro is correctly mounted
- ✅ Confirm
group_add: [video, render]is set in compose file - ✅ Test with
vainfoon the host to confirm VAAPI is functional
Problem: Streams failing to play
- ✅ Monitor channel status in admin interface
- ✅ Toggle between Go and FFmpeg modes in global settings
- ✅ Check per-source retry settings in source management
- ✅ Use dead stream management to mark problematic streams
Problem: High CPU usage
- ✅ Disable FFmpeg mode if hardware acceleration unavailable
- ✅ Use
-c copyinstead of transcoding in FFmpeg arguments - ✅ Reduce
maxConnectionsper source in admin interface - ✅ Monitor active connections in dashboard
Problem: Ad-break freezes on channels like Pluto TV
- ✅ Enable FFmpeg mode with
-mpegts_flags initial_discontinuityin pre-output args - ✅ Add
-fflags +genpts+discardcorrupt+igndtsto pre-input args - ✅ The stream watcher will detect and recover from prolonged stalls automatically
Problem: HDHomeRun not discovered by Plex/Emby
- ✅ Ensure your media server is on the same local network as KPTV Proxy
- ✅ HDHomeRun endpoints are restricted to RFC1918 addresses — public IPs are blocked
- ✅ If behind a reverse proxy, ensure
X-Forwarded-Foris set to the client's real IP
Problem: A group-filtered playlist (/pl/{username}/{password}/{group}) returns no channels for an XC source after upgrading
- ✅ The
{group}value must match the provider's category name now, notlive/vod/series. Checkgroup-titlein the unfiltered playlist or the channel list in the admin interface for the current value.
Network → Open Network Stream → http://your-server:PORT/pl/USERNAME/PASSWORD
Add-ons → PVR IPTV Simple Client
M3U Play List URL: http://your-server:PORT/pl/USERNAME/PASSWORD
Server URL: http://your-server:PORT
Username: your-xc-account-username
Password: your-xc-account-password
Playlist URL: http://your-server:PORT/pl/USERNAME/PASSWORD
Format: M3U8/HLS
- Admin Interface: Protected by Argon2id-hashed credentials and secure session cookies
- API Tokens: Stored as Argon2id hashes, shown only once, with granular permissions
- Network Security: Run behind reverse proxy (nginx/Cloudflare) for production
- HDHomeRun: Restricted to local network (RFC1918) only
- Source Privacy: Enable
obfuscateUrlsto hide provider URLs in logs - Container Security: Runs as non-root user (UID 1000)
- Custom CSS: Validate custom CSS to prevent XSS attacks
- XC Passwords: Use the built-in password generator for strong account credentials
{
"workerThreads": 20,
"maxConnectionsToApp": 500,
"ffmpegMode": true,
"ffmpegPreOutput": ["-c", "copy", "-f", "mpegts"]
}{
"workerThreads": 2,
"bufferSizePerStream": 4,
"maxConnectionsToApp": 50,
"ffmpegMode": false
}- XC cache is versioned. The first import after upgrading re-fetches every XC source's full catalog rather than reusing anything cached under the old shape.
- A failed XC fetch is no longer cached. If any of an XC source's six requests (live/series/vod streams plus their three category lists) fails, that import cycle isn't cached at all — it retries on the next
importRefreshIntervalinstead of serving a partial catalog for the full cache lifetime. - XC VOD is now imported. If VOD content wasn't showing up from an XC source before, check
vodIncludeRegex/vodExcludeRegexand the target XC output account'senableVODsetting after upgrading. - Group-filtered playlists for XC sources use provider category names now, not
live/vod/series. Update any saved/pl/{username}/{password}/{group}links accordingly — see Common Issues & Solutions above.
KPTV Proxy will always remain free and open-source. If this project has enhanced your IPTV experience, consider supporting its continued development:
https://www.paypal.com/paypalme/kevinpirnie
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
FFmpeg License Information:
- KPTV Proxy uses FFmpeg and FFprobe for stream processing and validation; they are not included in the container image
- FFmpeg is used as an external binary mounted from the host
- FFmpeg source code: https://ffmpeg.org/download.html
- FFmpeg is licensed under LGPL v2.1 or later
Patent Considerations: FFmpeg may use patented algorithms for various multimedia codecs. Patent laws vary by jurisdiction. For commercial use, consult legal counsel regarding potential patent licensing requirements in your jurisdiction.
MIT License - see LICENSE file for details.
- FFmpeg/FFprobe: Licensed under LGPL v2.1 or later - https://ffmpeg.org/legal.html
- TailwindCSS: MIT License - https://tailwindcss.com/
Need Help? Use the web admin interface at http://your-server:port/ for easy configuration management, customize the appearance with /settings/custom.css, or enable debug mode and check the logs for detailed information. The automatic Stream Watcher will help maintain stream reliability in the background, and FFmpeg integration provides advanced streaming capabilities for complex media formats.
Still Need Help? Hit me up on Discord: https://discord.gg/bd4Qan3PaN