Application log timestamps are pinned to UTC no matter what the operator
configures, while nginx in the same container honors TZ - one container,
two timezones (issue 1439). Two mechanisms force this:
1. docker/entrypoint.sh launches the app tree via `su - dispatch`,
which strips the environment; only whitelisted vars are re-exported
through /etc/environment and /etc/profile.d, and TZ is not among
them, so no app process ever sees the operator's declared zone.
2. Whitelisting TZ alone cannot fix Django-managed processes anyway:
Django's settings loader unconditionally re-stamps os.environ["TZ"]
= TIME_ZONE ("UTC") and calls time.tzset() in every uwsgi, celery
and management-command process. Stdlib logging's %(asctime)s renders
via time.localtime(), so it can never show local time in a Django
process regardless of the environment.
The fix, keeping TIME_ZONE = "UTC" / USE_TZ untouched (DB truth and
every wire surface - XMLTV offsets, XC server_info/time_now/EPG
timestamps - stay UTC by design):
- entrypoint: normalize a DISPATCHARR_TIME_ZONE bootstrap var from the
standard TZ env and whitelist it. TZ itself is deliberately NOT
whitelisted: pam_env would hand it to every su- child including
initdb/postgres, silently flipping the database server timezone on
fresh installs - the precondition for the EPG-offset corruption
class tracked in issue 651, and (with an invalid zone) a source of
psycopg "unknown PostgreSQL timezone" warnings emitted while the
connection lock is held. Verified empirically: with TZ whitelisted,
a fresh install ran its sessions at the container zone; without it,
the server default stays UTC.
- settings: capture DISPATCHARR_DISPLAY_TZ at module import, before
Django's tzset re-stamp, as the pre-database display default.
- logging: the verbose formatter renders timestamps with
datetime/ZoneInfo from an in-process cached zone - never
time.localtime(), and never a database query at emit time. An
emit-time query can self-deadlock: a log record that originates
inside a psycopg call (e.g. its timezone warning) would re-enter the
same non-reentrant connection lock the ORM query then needs. The
cache is refreshed out-of-band from provably safe contexts instead:
request_started, celery task_prerun, and a CoreSettings post_save
receiver (immediate in the process that saves the UI setting). The
zone resolves to the UI's System > Time Zone setting - already
canonical for DVR rules, celery crontabs and backup naming - with
the env capture as the value before the first refresh, and any
database error or invalid stored zone keeps the previous value.
- first-boot seed: the fresh-install default that the settings
consolidation migration writes for the system time zone now derives
from the same env capture (validated against zoneinfo, falling back
to UTC) instead of a hardcoded "UTC", so a new install honors the
declared container timezone from first boot. Existing installs are
untouched: the migration only manufactures a default when no stored
value exists, and installs that already ran it never re-run it.
Known residuals: uWSGI's native request log renders its own C-level
ftime outside Python logging and keeps UTC, as do celery's internal
worker_log_format lines; idle workers adopt a changed UI zone on their
next request/task. All documented rather than patched.
|
||
|---|---|---|
| .github | ||
| .idea | ||
| apps | ||
| core | ||
| dispatcharr | ||
| docker | ||
| docs/images | ||
| frontend | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .gitattributes | ||
| .gitignore | ||
| .python-version | ||
| CHANGELOG.md | ||
| CONTRIBUTING.md | ||
| debian_install.sh | ||
| fixtures.json | ||
| LICENSE | ||
| manage.py | ||
| Plugin_repo.md | ||
| Plugins.md | ||
| pyproject.toml | ||
| README.md | ||
| version.py | ||
🎬 Dispatcharr — Your Ultimate IPTV & Stream Management Companion
📖 What is Dispatcharr?
Dispatcharr (pronounced like "dispatcher") is an open-source powerhouse for managing IPTV streams, EPG data, and VOD content with elegance and control.
Born from necessity and built with passion, it started as a personal project by OkinawaBoss and evolved with contributions from legends like dekzter, SergeantPanda and Bucatini.
Think of Dispatcharr as the *arr family's IPTV cousin — simple, smart, and designed for streamers who want reliability and flexibility.
🎯 What Can I Do With Dispatcharr?
Dispatcharr empowers you with complete IPTV control. Here are some real-world scenarios:
💡 Consolidate Multiple IPTV Sources
Combine streams from multiple providers into a single interface. Manage, filter, and organize thousands of channels with ease.
📺 Integrate with Media Centers
Use HDHomeRun emulation to add virtual tuners to Plex, Emby, or Jellyfin. They'll discover Dispatcharr as a live TV source and can record programs directly to their own DVR libraries.
📡 Create a Personal TV Ecosystem
Merge live TV channels with custom EPG guides. Generate XMLTV schedules or use auto-matching to align channels with existing program data. Export as M3U, Xtream Codes API, or HDHomeRun device.
🔧 Transcode & Optimize Streams
Configure output profiles with FFmpeg transcoding to optimize streams for different clients (reduce bandwidth, standardize formats, or add audio normalization).
🔐 Centralize VPN Access
Run Dispatcharr through a VPN container (like Gluetun) so all streams route through a single VPN connection. Your clients access geo-blocked content without needing individual VPNs, reducing bandwidth overhead and simplifying network management.
🚀 Monitor & Manage in Real-Time
Track active streams, client connections, and bandwidth usage with live statistics. Monitor buffering events and stream quality. Automatic failover keeps viewers connected when streams fail—seamlessly switching to backup sources without interruption.
👥 Share Access Safely
Create multiple user accounts with granular permissions. Share streams via M3U playlists or Xtream Codes API while controlling which users access which channels, profiles, or features. Network-based access restrictions available for additional security.
🔌 Extend with Plugins
Build custom integrations using Dispatcharr's robust plugin system. Automate tasks, connect to external services, or add entirely new workflows.
✨ Why You'll Love Dispatcharr
✅ Stream Proxy & Relay — Intercept and proxy IPTV streams with real-time client management
✅ M3U & Xtream Codes — Import, filter, and organize playlists with multiple backend support
✅ EPG Matching & Generation — Auto-match EPG to channels or generate custom TV guides
✅ Video on Demand — Stream movies and TV series with rich metadata and IMDB/TMDB integration
✅ Multi-Format Output — Export as M3U, XMLTV EPG, Xtream Codes API, or HDHomeRun device
✅ Real-Time Monitoring — Live connection stats, bandwidth tracking, and automatic failover
✅ Stream Profiles — Configure how Dispatcharr connects to backend streams (VLC, FFmpeg, Streamlink, or custom commands)
✅ Output Profiles — Transcode what stream profiles deliver before it reaches the client (e.g. AC3 for media servers, AAC for browsers) with fMP4 or MPEG-TS container selection
✅ Multi-User & Access Control — Granular permissions and network-based access restrictions
✅ Plugin System — Extend functionality with custom plugins for automation and integrations
✅ Fully Self-Hosted — Total control, no third-party dependencies
Screenshots
🛠️ Troubleshooting & Help
- General help? Visit Dispatcharr Docs
- Community support? Join our Discord
🚀 Get Started in Minutes
🐳 Quick Start with Docker (Recommended)
docker pull ghcr.io/dispatcharr/dispatcharr:latest
docker run -d \
-p 9191:9191 \
--name dispatcharr \
-v dispatcharr_data:/data \
ghcr.io/dispatcharr/dispatcharr:latest
Customize ports and volumes to fit your setup.
🐋 Docker Compose Options
| Use Case | File | Description |
|---|---|---|
| All-in-One Deployment | docker-compose.aio.yml | ⭐ Recommended! A simple, all-in-one solution — everything runs in a single container for quick setup. |
| Modular Deployment | docker-compose.yml | Separate containers for Dispatcharr, Celery, Redis, and Postgres — perfect if you want more granular control. |
| Development Environment | docker-compose.dev.yml | Developer-friendly setup with pre-configured ports and settings for contributing and testing. |
🛠️ Building from Source
⚠️ Warning: Not officially supported — but if you're here, you know what you're doing!
If you are running a Debian-based OS, use the debian_install.sh script. For other OS, contribute a script and we’ll add it!
🤝 Want to Contribute?
We welcome PRs, issues, ideas, and suggestions!
- Prior to contributing, please read the CONTRIBUTING.md
Whether it's writing docs, squashing bugs, or building new features, your contribution matters! 🙋
📚 Documentation & Roadmap
- 📖 Documentation: Dispatcharr Docs
Upcoming Features (in no particular order):
- 🎬 VOD Management Enhancements — Granular metadata control and cleanup of unwanted VOD content
- 📁 Media Library — Import local files and serve them over XC API
- 👥 Enhanced User Management — Customizable XC API output per user account
- 🔌 Fallback Videos — Automatic fallback content when channels are unavailable
❤️ Shoutouts
A huge thank you to all the incredible open-source projects and libraries that power Dispatcharr. We stand on the shoulders of giants!
✉️ Connect With Us
Have a question? Want to suggest a feature? Just want to say hi?
➡️ Open an issue or reach out on Discord.
💖 Support Dispatcharr
Open Collective provides a transparent way for anyone who finds value in Dispatcharr to support things like: • Infrastructure costs (Domains, Servers, etc.) • Apple Developer Program and Google Play Developer accounts • Helping contributors dedicate more time to improving the project
Support is completely optional, and Dispatcharr will always remain free and open-source.
⚖️ License & Legal
Dispatcharr is licensed under GNU AGPL v3.0: For full license details, see LICENSE.
Dispatcharr is a trademark of the Dispatcharr project. Use of the Dispatcharr name or logo requires permission from the maintainers.