# IPTV Checker (iptvc) [![Последний релиз](https://img.shields.io/gitea/v/release/IPTV/iptvc?gitea_url=https%3A%2F%2Fgit.axenov.dev&display_name=release&color=green&cacheSeconds=600)](https://git.axenov.dev/IPTV/iptvc/releases/latest) Консольная программа для проверки IPTV-плейлистов в формате m3u или m3u8. > **Веб-сайт:** [m3u.su](https://m3u.su) > Документация: [m3u.su/docs](https://m3u.su/docs) > Telegram-канал: [@iptv_aggregator](https://t.me/iptv_aggregator) > Исходный код: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV) ## Установка Достаточно скачать и распаковать архив с подходящим исполняемым файлом [со страницы последнего релиза](https://git.axenov.dev/IPTV/iptvc/releases/latest): | ОС | Скачать для `amd64` | Скачать для `arm64` | | ------- | ---------------------------------- | ---------------------------------- | | Linux | [linux_amd64.zip][linux_amd64] | [linux_arm64.zip][linux_arm64] | | MacOS | [darwin_amd64.zip][darwin_amd64] | [darwin_arm64.zip][darwin_arm64] | | Windows | [windows_amd64.zip][windows_amd64] | [windows_arm64.zip][windows_arm64] | [linux_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_amd64.zip [darwin_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_amd64.zip [windows_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_amd64.zip [linux_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_arm64.zip [darwin_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_arm64.zip [windows_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_arm64.zip ## Компиляция Для сборки потребуется golang v1.23.6 и выше. На версиях ниже не проверялось. 1. Склонировать репозиторий 2. Находясь в корне репозитория, следует выполнить `make` или `make help` для получения справки. 3. Другой способ — выполнить `go run .` для быстрого запуска. ## Быстрый старт Открыть терминал в директории, куда распакован исполняемый файл `iptvc`. Выполнить `./iptvc help` для получения краткой справки. Если был клонирован репозиторий, то вместо `./iptvc` можно запустить `go run .` Ниже рассмотрены простые примеры использования программы для проверки плейлистов. ### Проверка файла плейлиста 1. Скачать любой файл плейлиста, сохранив его в файл с именем, например, `mypls.m3u` 2. Выполнить команду `./iptvc check -f mypls.m3u` Можно указывать множество разных файлов (каждый с `-f`) и комбинировать с другими аргументами. ### Проверка плейлиста по ссылке 1. Найти прямую ссылку на плейлист в интернете, например, `http://m3u.su/XYZ` 2. Выполнить команду `./iptvc check -u http://m3u.su/XYZ` Можно указывать множество разных ссылок (каждый с `-u`) и комбинировать с другими аргументами. ### Проверка плейлиста из ini-списка Подробности об ini-файле и его формате можно прочесть здесь: https://git.axenov.dev/IPTV/playlists 1. Скачать файл [`playlists.ini`](https://git.axenov.dev/IPTV/playlists/raw/branch/master/playlists.ini) или создать локальный файл в аналогичном формате (например, `./test.ini`) 2. Выполнить команду `./iptvc check` или `./iptvc check -i playlist.ini` для проверки всех плейлистов из файла `./playlists.ini` 3. Выполнить команду `./iptvc check -i test.ini -c ABC`, чтобы проверить только плейлист с кодом `ABC` из файла `./test.ini` Если `-i` не указан явно, то будет попытка прочитать файл `playlists.ini`, находящийся в одной директории с iptvc. Аргумент `-i` можно указывать только однажды, но его можно комбинировать с `-f` и `-u`. ### Другие возможности команды `check` * `--random|-r X` — проверить X случайных плейлистов из ini-файла * `--json|-j` — вывести результаты проверки в формате JSON * `--quiet|-q` — полностью подавить вывод лога (включая отладочную информацию) * `--verbose|-v` — добавить в лог более подробную отладочную информацию (значительно увеличит количество строк!) * `--tags|-t` — файл с перечислением тегов (подробности см. [здесь](https://git.axenov.dev/IPTV/playlists#файл-channelsjson)) Например, можно получить только json с результатами, передать его в `jq` и, отфильтровав результат, вывести названия оффлайн каналов: ``` ./iptvc check ... -j -q | jq '.[].channels[] | select(.isOnline == false).title' ``` > [!NOTE] > Набери `./iptvc help` для получения помощи. ## Веб-интерфейс Программа включает встроенный веб-сервер для просмотра плейлистов и результатов их проверки. ### Запуск ``` ./iptvc serve -i playlists.ini -p 8080 ``` ### Параметры команды `serve` * `-p, --port` — порт для веб-сервера (переопределяет `config.yml` и `WEB_PORT`); * `--host` — хост для привязки (переопределяет `config.yml` и `WEB_HOST`); * `--check` — включить фоновую проверку плейлистов (по умолчанию выключена). При указании `--check` доступны флаги проверки: * `-i, --ini` — путь к ini-файлу (по умолчанию `./playlists.ini`); * `-t, --tags` — путь к файлу тегов (по умолчанию `./channels.json`); * `-r, --random` — проверить N случайных плейлистов из ini-файла; * `--every` — интервал между проверками в секундах (по умолчанию `60`); * `--repeat` — количество циклов проверки (по умолчанию `0` — бесконечно). ### Конфигурация Приоритет настроек (от низшего к высшему): 1. **Значения по умолчанию** — встроены в код; 2. **`config.yml`** — YAML-файл в корне проекта (путь можно задать через флаг `--config`); 3. **Переменные окружения** — переопределяют значения из `config.yml` (если заданы); 4. **CLI-флаги** — переопределяют значения из окружения и `config.yml` (если заданы явно). Флаги `--port` и `--host` переопределяют конфигурацию только если переданы явно. Если флаг не указан, используется значение из переменной окружения, затем из `config.yml`, затем значение по умолчанию. Файл `.env` загружается автоматически, переменные из него применяются как переменные окружения. #### `config.yml` ```yaml app: title: IPTV Checker timezone: GMT debug: false log_level: info server: host: localhost port: 8080 base_url: http://localhost:8080 page_size: 0 repo_url: https://git.axenov.dev/IPTV check: playlists: user-agent: - Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer timeout: [0, 10000] # ms, макс время ожидания ответа при проверке каждого плейлиста all-cooldown: [0, 10000] # ms, задержка между проверками всех плейлистов one-cooldown: [0, 10000] # ms, задержка между проверками каждого плейлиста per-routine: [0, 10000] # количество одновременно проверяемых плейлистов channels: user-agent: Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer timeout: 10 # sec, макс время ожидания ответа при проверке каждого канала byte-range: 512 # bytes, количество байт для получения от сервера all-cooldown: 0 # ms, задержка между проверками всех каналов плейлиста one-cooldown: 0 # ms, задержка между проверками каждого канала плейлиста per-routine: 10 # количество одновременно проверяемых каналов cache: enabled: false host: localhost port: 6379 username: password: db: 1 ttl: 1800 ``` Параметры `check.playlists` и `check.channels` (кроме `byte-range`) могут быть заданы как скаляр или массив `[min, max]`. При массиве каждый раз выбирается случайное значение в диапазоне. `user-agent` может быть строкой или массивом строк (случайный выбор). `byte-range` — всегда целое число. #### Переменные окружения | Переменная | Соответствует в `config.yml` | Описание | | ---------------- | ---------------------------- | ----------------------------------- | | `APP_DEBUG` | `app.debug` | Режим отладки | | `APP_TITLE` | `app.title` | Заголовок сайта | | `APP_TIMEZONE` | `app.timezone` | Часовой пояс | | `APP_URL` | `server.base_url` | Базовый URL для ссылок | | `CACHE_ENABLED` | `cache.enabled` | Включить кеш (KeyDB/Redis) | | `CACHE_HOST` | `cache.host` | Хост KeyDB/Redis | | `CACHE_PORT` | `cache.port` | Порт KeyDB/Redis | | `CACHE_USERNAME` | `cache.username` | Имя пользователя KeyDB/Redis | | `CACHE_PASSWORD` | `cache.password` | Пароль KeyDB/Redis | | `CACHE_DB` | `cache.db` | Номер БД KeyDB/Redis | | `CACHE_TTL` | `cache.ttl` | TTL записей в кеше (сек) | | `WEB_PORT` | `server.port` | Порт веб-сервера | | `WEB_HOST` | `server.host` | Хост для привязки | | `PAGE_SIZE` | `server.page_size` | Размер страницы (0 — без пагинации) | | `REPO_URL` | `server.repo_url` | Ссылка на репозиторий | ### Маршруты | Метод | Путь | Описание | | ----- | ----------------------- | ---------------------------------------- | | GET | `/` | Главная страница со списком плейлистов | | GET | `/page/{N}` | Страница N списка плейлистов | | GET | `/{code}` | Редирект на прямую ссылку плейлиста | | GET | `/{code}.m3u[8]` | Редирект на прямую ссылку плейлиста | | GET | `/{code}/details` | Страница с описанием плейлиста | | GET | `/api/playlists/{code}` | JSON: информация о плейлисте | | GET | `/api/version` | JSON: версии компонентов | | GET | `/api/health` | JSON: состояние сервиса | | GET | `/api/stats` | JSON: статистика по плейлистам и каналам | ### Связь с проверкой Веб-сервер отображает данные из кеша KeyDB/Redis, который заполняется командой `check`. Если кеш недоступен, все плейлисты отображаются со статусом `unknown`. Для обновления данных в фоне запустите `serve` с флагом `--check`: ``` ./iptvc serve -i playlists.ini -p 8080 --check ``` Результаты проверок появляются на веб-страницах немедленно после проверки каждого плейлиста, не дожидаясь завершения полного цикла. Можно запускать `serve` и `check` отдельными процессами: ``` ./iptvc check --repeat 0 --every 60 & ./iptvc serve ``` Или используйте docker-окружение проекта. ## Результаты проверки Программа логирует процесс и результаты своей работы. Рассмотрим лог на примере. В рабочей директории лежит файл `playlists.ini`, в котором минимально описано два плейлиста: ```ini [first] pls='https://example.com/list1.m3u' [second] pls='https://example.com/list2.m3u' ``` Программа запущена следующим образом: `./iptvc check -c first` (чтобы проверить только плейлист с кодом `first` из ini-файла). Вывод будет примерно таким: ``` 2025/01/02 12:34:00 Loading playlists from ini-file: /home/user/playlists.ini 2025/01/02 12:34:00 Loaded 2 playlists 2025/01/02 12:34:00 [001/001] Playlist [first] 2025/01/02 12:34:00 Fetching... (https://example.com/list1.m3u) 2025/01/02 12:34:00 Parsing content... 2025/01/02 12:34:00 Parsed, checking channels (114)... 2025/01/02 12:34:00 Check parameters calculated: count=114 timeout=8.00s routines=12 2025/01/02 12:34:12 Checked successfully! online=101 onlinePercent=88.60% offline=13 offlinePercent=11.40% elapsedTime=12.39s ``` Разберём построчно: 1. Загрузка ini-файла 2. Файл загружен, в нём 2 плейлиста 3. Начало обработки плейлиста `first` 4. Скачивание плейлиста `first` по ссылке `https://example.com/list1.m3u` в оперативную память 5. Плейлист скачан, начало разбора плейлиста 6. Плейлист разобран, начало проверки каналов (114 штук) 7. Определены параметры проверки (подробности ниже) 8. (спустя время) Проверка успешно завершена: онлайн каналов 101 (88.60% от всех), оффлайн каналов 13 (11.40% от всех), затрачено 12 секунд. ### Параметры проверки Выше в п.7 видно некоторые служебные данные: * `timeout` — таймаут каждого запроса в секундах (макс. время ожидания ответа канала); * `routines` — количество одновременных проверок. Эти параметры рассчитываются динамически для каждого плейлиста в отдельности, исходя из количества каналов в каждом (`count`). См. [app/checker/checker.go](app/checker/checker.go) для подробностей. Идея в том, чтобы найти баланс между скоростью проверки и качеством: * чем ниже коэффициент `k`, тем больше горутин, меньше таймаут, быстрее проверка, хуже результаты; * чем выше коэффициент `k`, тем меньше горутин, больше таймаут, медленнее проверка, лучше результаты. На скорость проверки влияют: * количество горутин (чем выше, тем больше каналов проверяется параллельно); * таймаут (тем ниже, тем быстрее закончится проверка канала); * количество каналов (чем больше, тем дольше общий процесс); * скорость ответа сервера (чем выше, тем хуже) и количество данных, которые он отдаёт (чем больше, тем хуже). На качество проверки влияет таймаут: * чем выше, тем выше вероятность получить успешный ответ от сервера, транслирующего поток; * чем ниже, тем выше вероятность не дождаться успешного ответа и засчитать канал нерабочим. > [!NOTE] > Логика балансирования будет уточняться и корректироваться по мере развития проекта, исходя из реального применения. ### Коды возврата * 0 — успех * 1 — общая ошибка, см. вывод * 2 — команде `check` не переданы параметры `--file`, `--url` и `--code` ## Лицензия ПО распространяется на условиях [лицензии MIT](LICENSE).