A modern web-based IPTV proxy with advanced filtering, tag-based playlist generation, and multi-account support.
✅ Web UI - Easy-to-use interface for managing accounts, filters, and rulesets
✅ Multiple Accounts - Manage multiple IPTV services from one place
✅ Advanced Filtering - Filter by category, channel name, or regex
✅ Tag Extraction - Automatically extract and normalize tags from channel names
✅ Custom Rulesets - Create provider-specific tag extraction rules
✅ Tag-Based Playlists - Generate playlists filtered by tags
✅ Database-First EPG - EPG data synced to database for fast, reliable program guides
✅ Multi-Source EPG - Supports Schedules Direct and XMLTV sources
✅ Xtream Codes API - Connect IPTV clients (TiviMate, IPTV Smarters) using standard API format
Using the pre-built image from GitHub Container Registry:
docker run -d \
--name iptv-proxy-v2 \
-p 8889:8000 \
-v ./data:/app/data \
-e SECRET_KEY=your-secret-key-here \
ghcr.io/klopstack/iptv-proxy-v2:latestOr using docker-compose:
# Create docker-compose.yml (see example below)
docker-compose up -dAccess at: http://localhost:8889
# Install dependencies
pip install -r requirements.txt
# Run the application
python app.pyAccess at: http://localhost:8000
version: '3.8'
services:
iptv-proxy-v2:
image: ghcr.io/klopstack/iptv-proxy-v2:latest
container_name: iptv-proxy-v2
restart: unless-stopped
ports:
- "8889:8000"
volumes:
- ./data:/app/data
environment:
PORT: "8000"
SECRET_KEY: "${SECRET_KEY:-change-me-in-production}"
DEBUG: "False"- Navigate to the Accounts page
- Click Add Account
- Fill in your IPTV service details:
- Name: Friendly name for this account
- Server: Your IPTV server (without http://)
- Username: Your IPTV username
- Password: Your IPTV password
- Click Save
- Use the Test button to verify the connection
- Navigate to the Filters page
- Click Add Filter
- Select an account
- Choose filter type:
- Category: Filter by category name (e.g., "UK", "SPORT")
- Channel Name: Filter by channel name (e.g., "BBC", "News")
- Regex: Advanced pattern matching
- Choose action:
- Whitelist: Only include matching channels
- Blacklist: Exclude matching channels
- Enter the filter value
- Click Save
- Navigate to the Preview Channels page
- Select an account
- Click Preview Channels to see filtered results
- Download the M3U file when satisfied
M3U Playlist URL:
http://localhost:8889/playlist/<account_id>.m3u
EPG URL:
http://localhost:8889/epg/<account_id>.xml
Replace <account_id> with your account ID (shown in the UI).
- Type: Category
- Action: Whitelist
- Value: UK
- Type: Category
- Action: Blacklist
- Value: ADULT
- Type: Channel Name
- Action: Whitelist
- Value: Sport
- Type: Regex
- Action: Blacklist
- Value: 24/7|24-7
The proxy includes a powerful tag extraction system that parses channel and category names to extract metadata tags. These tags can be used for advanced filtering and playlist generation.
Pattern Types:
- Prefix: Match text at the start (e.g., "US|")
- Suffix: Match text at the end (e.g., "HD")
- Contains: Match text anywhere (e.g., "Sports")
- Regex: Advanced pattern matching (e.g., "^(US|CA)|")
Special Tag Names:
__CLEANUP__: Remove pattern without creating a tag__LOCATION__: Extract[bracketed]content as tag__CALLSIGN__: Extract(parenthesized)content as tag__CAPTURE__: Extract first regex capture group as tag
PPV Control (NEW): Each tag rule can now control the PPV (pay-per-view) flag on matching channels:
- Keep: Don't modify the channel's is_ppv value (default)
- Set True: Force channels to be marked as PPV
- Set False: Force channels to NOT be marked as PPV
This is useful for cases like Bally Sports/FanDuel Sports Network channels that are in "PPV" categories but aren't actually pay-per-view events.
Example 1: Extract Country Codes
{
"name": "Country Code",
"pattern": "^([A-Z]{2})\\|",
"pattern_type": "regex",
"tag_name": "__CAPTURE__",
"source": "channel_name",
"remove_from_name": true
}Matches: "US| ESPN" → Tag: "US", Clean name: "ESPN"
Example 2: Fix Bally Sports PPV Mislabeling
{
"name": "Bally Sports Not PPV",
"pattern": "Bally Sports|FanDuel Sports",
"pattern_type": "regex",
"source": "category_name",
"tag_name": "REGIONAL",
"set_is_ppv": "set_false"
}Marks Bally Sports channels as NOT PPV, even if they're in a "PPV" category.
Example 3: Mark Actual PPV Events
{
"name": "PPV Events",
"pattern": "UFC|Boxing Match|WWE PPV",
"pattern_type": "regex",
"source": "channel_name",
"tag_name": "PPV_EVENT",
"set_is_ppv": "set_true"
}Forces specific event channels to be marked as PPV.
- Navigate to Tags & Rulesets page
- Click New Ruleset
- Give it a name and description
- Add tag rules to the ruleset
- Assign the ruleset to accounts
- Click Discover Tags to process channels
For detailed documentation, see:
# List accounts
GET /api/accounts
# Create account
POST /api/accounts
{
"name": "My IPTV",
"server": "example.com",
"username": "user",
"password": "pass",
"enabled": true
}
# Update account
PUT /api/accounts/<id>
# Delete account
DELETE /api/accounts/<id>
# Test account connection
POST /api/accounts/<id>/test
# Get categories
GET /api/accounts/<id>/categories
# Get statistics
GET /api/accounts/<id>/stats# List filters
GET /api/filters
# List filters for account
GET /api/accounts/<account_id>/filters
# Create filter
POST /api/filters
{
"account_id": 1,
"name": "UK Only",
"filter_type": "category",
"filter_action": "whitelist",
"filter_value": "UK",
"enabled": true
}
# Update filter
PUT /api/filters/<id>
# Delete filter
DELETE /api/filters/<id># Generate M3U
GET /playlist/<account_id>.m3u
# Get EPG
GET /epg/<account_id>.xml
# Preview channels
GET /api/accounts/<account_id>/preview?limit=100# Connect IPTV clients using standard Xtream API format
# Configure in client:
# Server: http://your-proxy:8000
# Username: [your-credential-username]
# Password: [your-credential-password]
# Main API endpoint
GET /player_api.php?username=X&password=Y&action=get_live_streams
# EPG endpoint
GET /xmltv.php?username=X&password=Y
# Manage credentials
GET /api/xtream-credentials
POST /api/xtream-credentials
PUT /api/xtream-credentials/<id>
DELETE /api/xtream-credentials/<id>See docs/XTREAM_CODES_API.md for complete documentation.
pip install -r requirements.txt
pip install -r requirements-dev.txtOr use the Makefile:
make install# Run tests with coverage (75% minimum required)
pytest tests/ -v --cov=. --cov-report=html --cov-report=term-missing
# Or use Makefile
make test
# Fast test without coverage
make test-fast# Run all linting checks
make lint
# Format code automatically
make format
# Individual linting tools
flake8 .
black --check .
isort --check-only .
mypy app.py models.py services/The project uses GitHub Actions to automatically run tests and linting on all pull requests and commits to main/develop branches. The CI pipeline:
- Linting: flake8, black, isort, mypy
- Testing: pytest with minimum 75% code coverage
- Multi-version: Tests run on Python 3.9, 3.10, and 3.11
The database is automatically created on first run. To reset:
rm data/iptv_proxy.db
python app.py # Will recreate database| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:///iptv_proxy.db |
Database connection string |
PORT |
8000 |
Server port |
SECRET_KEY |
dev-secret-key... |
Flask secret key |
DEBUG |
False |
Enable debug mode |
iptv-proxy-v2/
├── app.py # Main application
├── models.py # Database models
├── services/
│ ├── iptv_service.py # IPTV API client
│ └── cache_service.py # Caching layer
├── templates/ # HTML templates
│ ├── base.html
│ ├── index.html
│ ├── accounts.html
│ ├── filters.html
│ └── test.html
├── tests/
│ └── test_app.py # Test suite
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md
The v2 proxy is a complete rewrite with a database backend. It is not backward compatible with the v1 environment variable configuration.
To migrate:
- Deploy v2 alongside v1
- Add your accounts via the web UI
- Configure filters via the web UI
- Test the playlists
- Update your TVHeadend/app URLs to point to v2
- Remove v1 when satisfied
Existing installations: If you're experiencing slow performance when selecting accounts on the preview page, the database migrations will automatically add indexes on the next container restart. For immediate effect:
# Docker
docker exec -it iptv-proxy-v2 python run_migrations.py
# or just restart
docker-compose restart iptv-proxy-v2
# Manual installation
python run_migrations.pyThe migration system runs automatically on container startup and is completely idempotent. See PERFORMANCE.md for details.
If running in Docker with a volume, ensure the data directory is writable:
chmod 777 data/- Check filter is enabled
- Use the Preview feature to test
- Check logs:
docker-compose logs -f iptv-proxy-v2 - Clear cache: Click "Clear Cache" button in UI
- Use the "Test" button on the account
- Verify server/username/password
- Check firewall rules
- Try accessing the server directly from the container:
docker exec -it iptv-proxy-v2 curl http://your-server/player_api.php?username=x&password=y
Part of the MediaStack project.
For issues, questions, or contributions, see the main MediaStack repository.