Real-Time IPTV Stream Validation & Quality Monitoring Dashboard
Features • Installation • Usage • Configuration • Dashboard
StreamWatcher is a professional-grade IPTV stream validator with a real-time web dashboard. Designed for network engineers, ISPs, and content providers who need reliable stream quality monitoring and channel validation. Features sequential testing to isolate server-side issues, cumulative quality metrics, and beautiful live analytics.
- 🔄 Sequential Testing - Test channels one at a time to isolate server-side performance issues
- 📊 Real-time Dashboard - Live updates every second with progress tracking
- 🔁 Loop Testing - Single run, loop X times, or infinite loop modes
- 🎬 Resolution Detection - Automatic 720p, 1080p, and 4K detection with icons
- 📈 Cumulative Metrics - Track buffering and disconnects across all loop iterations
- 🌐 External M3U Links - Load playlists from URLs or local files
- ⏱️ Total Time Tracking - Cumulative time display from initial start
- 🌓 Dark Mode - Toggle between light and dark themes
- 🔍 Channel Selection UI - Interactive GUI with group filtering and search
- Stream Validation - Uses
ffprobeto detect video/audio streams - Resolution Detection - Automatically identifies 720p (HD), 1080p (Full HD), and 4K (Ultra HD)
- Buffering Detection - Tracks buffering events and counts occurrences
- Disconnect Tracking - Monitors connection failures and reconnection attempts
- Configurable Duration - Set custom test duration (1s - 999s) with time units (seconds/minutes/hours)
- Sequential Execution - Tests one channel at a time to prevent local system bottlenecks
| Mode | Description |
|---|---|
| Single Run | Test all channels once |
| Loop X Times | Repeat testing for a specified number of iterations (1-100+) |
| Infinite Loop | Continuous testing until manually stopped |
- Live Progress Bar - Visual progress indicator
- Status Indicators - Pending (gray), Testing (blue), Pass (green), Issue (red)
- Resolution Icons - Visual indicators for 720p, 1080p, and 4K streams
- Buffering Count - Total buffering events across all loops
- Disconnect Count - Cumulative disconnections across iterations
- Details Column - Error messages, stream information, and resolution data
- Dark Mode - Eye-friendly dark theme with localStorage persistence
- Responsive Design - Adapts to different screen sizes
- Python 3.13+ (tested on 3.13.7)
- ffprobe (part of FFmpeg package)
- Linux/macOS/Windows with terminal access
Ubuntu/Debian:
sudo apt update
sudo apt install ffmpegmacOS:
brew install ffmpegWindows: Download from ffmpeg.org and add to PATH
git clone https://github.com/Nigel1992/streamwatcher.git
cd streamwatcherpython3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activatepip install -r requirements.txtpython run_local_test.py <path_to_m3u_file_or_url>Examples:
# Local M3U file
python run_local_test.py data/test_sample.m3u
# External M3U URL
python run_local_test.py https://example.com/playlist.m3u8When you run the script, a GUI window will appear:
- Select Channels - Choose channels from groups or search by name
- Set Duration - Enter test duration (e.g., 15 seconds, 5 minutes, 1 hour)
- Choose Loop Mode:
- Single Run
- Loop X Times (specify iterations)
- Infinite Loop
- Click "Start Testing"
The dashboard opens automatically in your default browser at:
http://localhost:9001/results.html
Press Ctrl+C in the terminal to stop the test runner.
Your M3U playlist should follow the standard format. The URLs can be any stream format that ffprobe supports (HLS .m3u8, direct .ts, RTSP, HTTP streams, etc.):
#EXTM3U
#EXTINF:-1 tvg-id="channel1" tvg-name="Channel Name" tvg-logo="logo.png" group-title="Group",Channel Name
https://stream.example.com/channel1/playlist.m3u8
#EXTINF:-1 tvg-id="channel2" tvg-name="Another Channel" group-title="Group",Another Channel
http://stream.example.com/live/channel2.ts
#EXTINF:-1 tvg-id="channel3" tvg-name="RTSP Stream" group-title="Group",RTSP Stream
rtsp://stream.example.com:554/live/channel3Default HTTP port: 9001
To change the port, edit run_local_test.py:
HTTP_PORT = 9001 # Change to your preferred port- Minimum: 1 second
- Maximum: No hard limit (can use days/hours/minutes/seconds units)
- Default: 15 seconds
- Loop X Times: 1-100+ iterations
- Infinite: Runs until stopped manually
The dashboard displays:
| Column | Description |
|---|---|
| Channel | Channel name with resolution icon |
| Status | Current status (pending/testing/pass/issue) |
| Resolution | Detected resolution with icon (720p/1080p/4K) |
| Tested | Seconds tested for current iteration |
| Disconnects | Total disconnection count (cumulative) |
| Buffering | Total buffering event count (cumulative) |
| Details | Stream information or error messages |
- 🔵 Testing - Currently being tested
- ⚪ Pending - Waiting to be tested
- 🟢 Pass - Stream validated successfully
- 🔴 Issue - Buffering or connection errors detected
When using loop modes, the dashboard shows:
- Single Run: No loop indicator
- Loop X Times: "Loop Iteration: 3/5"
- Infinite Loop: "Infinite Loop - Iteration: 7"
streamwatcher/
├── run_local_test.py # Main test runner
├── results.html # Dashboard interface
├── requirements.txt # Python dependencies
├── data/
│ └── test_sample.m3u # Sample M3U playlist
├── src/
│ └── iptv_monitor/
│ ├── config.py # Configuration
│ ├── db.py # Database operations
│ └── worker.py # Stream testing logic
└── README.md # This file
Sequential Testing (default):
- Tests one channel at a time
- Isolates server-side performance issues
- Prevents local system resource bottlenecks
- Recommended for accurate server validation
When using loop modes, the following metrics persist across iterations:
- Buffering Count - Cumulative total across all loops
- Disconnect Count - Total disconnections across iterations
- Total Time - Cumulative time from initial test start
Test results are stored in SQLite database:
iptv_monitor.db
Contains:
- Channel information
- Test history
- Metrics and timestamps
If port 9001 is occupied:
sudo lsof -i :9001 | grep -v COMMAND | awk '{print $2}' | xargs -r sudo kill -9Or change the port in run_local_test.py.
Ensure FFmpeg is installed:
ffprobe -versionIf not installed, see Installation section.
On Linux, you may need to kill ports with sudo:
sudo fuser -k 9001/tcpManually navigate to:
http://localhost:9001/results.html
[INFO] Found 10 channels. Opening channel selector...
[INFO] Selected 10 channels for testing.
[INFO] Test duration set to 15 seconds
[INFO] Loop mode: Loop 5 times
[INFO] Starting iteration 1/5
Reading local file data/test_sample.m3u
Imported 10 channels
Starting 10 checks (duration=15s)...
Results:
3ABN Canada: pass - [video detected] [audio detected] [video detected 1280x720]
3ABN English: pass - [video detected] [audio detected] [video detected 1920x1080]
...
[INFO] Iteration 1 complete. Looping again...
[INFO] Starting iteration 2/5
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- FFmpeg team for the excellent
ffprobetool - The IPTV community for format standards and inspiration
- All contributors who help improve this project
If you encounter any issues or have questions:
- Check the Troubleshooting section
- Open an issue
- Start a discussion
⭐ If you find this project useful, please consider giving it a star! ⭐
Made with ❤️ by Nigel1992