26 KiB
Инструкции для работы с репозиторием
Обзор проекта
iptvc (IPTV Checker) — консольное приложение на Go для проверки IPTV-плейлистов в форматах M3U/M3U8. Программа умеет загружать плейлисты из локальных файлов, по URL и из ini-файла, проверять доступность плейлистов и отдельных каналов, выводить результаты в журнале или JSON, а также запускать встроенный веб-интерфейс.
Проект является частью экосистемы m3u.su. Исходный код размещается на Gitea: https://git.axenov.dev/IPTV/iptvc.
Основные технологии:
- Go 1.23.6 или новее согласно
go.modи README. - Cobra для CLI-команд и флагов.
- YAML для конфигурации.
- INI для списка плейлистов.
- Кеш через
github.com/redis/go-redis/v9для кеширования результатов. godotenvдля автоматической загрузки.env.- Docker и Docker Compose для контейнерного запуска.
- Встроенный HTTP-веб-сервер для просмотра плейлистов и результатов проверки.
Структура репозитория
main.go— точка входа, вызываетcmd.Execute().cmd/— CLI-слой на Cobra:root.go— корневая команда, глобальные persistent-флаги (--config,--verbose,--debug,--log-level).check.go— командаcheck: одно-/многоитерационная проверка плейлистов с выводом в журнал или JSON.serve.go— командаserve: HTTP-веб-сервер, при необходимости запускает фоновую проверку через--checkилиcheck.startOnServe.version.go— командаversion, печатаетiptvc v<VERSION>.flags.go— определение общих флагов дляcheck/serveи функцииapplyAppOverrides/applyCacheOverrides/applyCheckOverrides(используютcmd.Flags().Changed(), поэтому срабатывают только при явной передаче).flags_test.go— тесты применения CLI-переопределений к конфигурации.
app/— прикладная логика приложения.app/app.go— инициализация приложения и глобальных структурArgs/Config/Cache, точка входаapp.Init()/app.InitCache().app/checker/— подготовка и проверка плейлистов и каналов.app/cache/— абстракции и работа с кешем (черезgo-redis/v9).app/config/— структуры конфигурации, значения по умолчанию, YAML, переменные окружения и тесты.app/inifile/— чтение ini-файлов со списками плейлистов.app/playlist/— модели и обработка IPTV-плейлистов.app/tagfile/— чтение файла тегов каналов.app/web/— веб-сервер, маршруты, шаблоны, OpenAPI-спецификация и отображение данных (server.go,handlers.go,views.go,templates.go,openapi.go).app/logger/— настройка журналирования.app/utils/— вспомогательные функции.docker/cache/— конфигурация и данные для контейнера кеша (valkey.conf).channels.json— локальный файл тегов каналов.playlists.ini.example— пример ini-файла со списками плейлистов.config.yml.example— пример конфигурации приложения..env.example— пример переменных окружения.compose.yml— окружение из приложения, документации и кеша.Dockerfile— минимальный runtime-образ наalpine:3.22.5; берёт уже собранный бинарь изbin/linux_${TARGETARCH}/iptvc.Makefile— очистка, кросс-компиляция бинарей и образов (см. раздел «Сборка и запуск»).README.md— пользовательская документация, команды запуска, конфигурация и API-маршруты.LICENSE— лицензия MIT.
Архитектура и поток выполнения
main.goвызываетcmd.Execute().cmd/root.goрегистрирует глобальные флаги и дочерние Cobra-команды.- Команда
checkинициализирует приложение, применяет CLI-переопределения, подключает кеш, получает плейлисты и запускает проверку. - Команда
serveподнимает веб-сервер и при необходимости запускает фоновую проверку через флаг--checkили настройкуcheck.startOnServe. - Конфигурация загружается со следующим приоритетом: встроенные значения по умолчанию,
config.yml, переменные окружения и явно переданные CLI-флаги. - Результаты проверки могут сохраняться в кеш и отображаться веб-сервером. При недоступном кеше веб-интерфейс показывает неизвестный статус.
Не следует помещать бизнес-логику в main.go или CLI-команды, если её можно разместить в соответствующем пакете app/. CLI-слой должен отвечать за разбор аргументов, инициализацию и координацию прикладных компонентов.
Сборка и запуск
Для локальной разработки требуется Go версии 1.23.6 или новее. Dockerfile использует alpine:3.22.5 как базовый runtime-образ; бинарный файл собирается на хосте через go build и копируется в образ.
Основные команды:
# Показать доступные цели Makefile
make help
# Быстро запустить приложение из исходников
go run .
# Запустить CLI-справку
go run . help
# Проверить локальный плейлист
go run . check -f mypls.m3u
# Проверить плейлист по URL
go run . check -u https://example.com/playlist.m3u
# Запустить веб-интерфейс на порту 8800
go run . serve -p 8800
# Запустить веб-интерфейс с фоновой проверкой
go run . serve -i playlists.ini -p 8800 --check
# Собрать текущую платформу
go build -o iptvc .
# Запустить тесты всех пакетов
go test ./...
# Проверить форматирование
gofmt -w .
В блоке выше команда форматирования приведена как ориентир: gofmt следует запускать по Go-файлам, например gofmt -w main.go cmd app, если оболочка или используемая версия инструмента не поддерживает обработку директорий так, как ожидается.
Цели Makefile:
make clear— удалить каталогbin/с артефактами сборки.make linux GOARCH=amd64— собрать Linux-бинарный файл и ZIP-архив.make win GOARCH=amd64— собрать Windows-бинарный файл и ZIP-архив.make darwin GOARCH=amd64— собрать macOS-бинарный файл и ZIP-архив.make release— собрать архивы для Linux, Windows и macOS подamd64иarm64.make test— запустить все тесты (go test ./...).make image— собрать одноархитектурный runtime-образgit.axenov.dev/iptv/iptvc:latest(по умолчанию подlinux/amd64; переопределяется черезGOARCH).make image-all— собрать и запушить multi-arch манифест в registry (по умолчаниюlinux/amd64,linux/arm64; переопределяется черезIMAGE_PLATFORMS).
По умолчанию GOARCH=amd64. Поддерживаемые значения: amd64 и arm64.
Бинарники собираются на хосте через go build с кросс-компиляцией (CGO_ENABLED=0 + GOOS/GOARCH). Это справедливо для всех шести целевых платформ (linux/darwin/windows × amd64/arm64) и работает одинаково на любом хосте с Go 1.23+.
Образы собираются в Docker через docker build (одноархитектурный) или docker buildx build --platform ... --push (multi-arch). Dockerfile берёт уже собранный бинарь из build context (bin/linux_${TARGETARCH}/iptvc), а не собирает его сам — поэтому build context должен содержать нужный бинарь перед запуском make image/make image-all. make image и make image-all автоматически зависят от make linux, чтобы контекст был полным.
Multi-arch образы (make image-all) используют docker buildx и всегда пушат результат в registry. Это ограничение buildx: multi-arch манифест нельзя положить в локальный Docker daemon (--load не работает с несколькими платформами одновременно). Если нужен только локальный образ одной архитектуры — используйте make image.
Сжатие UPX не используется намеренно: UPX ломает нотаризацию Mach-O на современных macOS и снижает надёжность запуска Windows-бинарей.
Экономия от -ldflags="-s -w" (~30%) сохраняется.
Версия и коммит вкомпилируются в бинарь через -ldflags="-X axenov/iptv-checker/app.VERSION=... -X axenov/iptv-checker/app.COMMIT=..."; переменные берутся из git describe и git rev-parse на хосте в момент запуска make.
Сборка конкретной версии (по тегу или коммиту)
Makefile всегда берёт код из текущей рабочей копии (COPY . . в Dockerfile) и версию из git describe/git rev-parse на хосте в момент запуска. Поэтому, чтобы собрать произвольную версию, нужно сначала переключить рабочую копию на нужный тег или коммит, а затем запустить make.
Makefile сам не делает git checkout и не использует git archive — это осознанный выбор. Сборка остаётся детерминированной относительно того, что лежит в репозитории, а не относительно того, что пользователь хотел собрать. Любые попытки "обмануть" мету через make VERSION=v1.0.0 без git checkout приведут к тому, что в бинарь попадёт код текущей ветки с чужой версией в ldflags.
Пример: собрать релиз по тегу v1.0.0
# 1. Убедиться, что рабочая копия чистая (без незакоммиченных правок).
# Иначе `git checkout` откажется переключаться.
git status
# 2. Запомнить, на чём мы были, чтобы вернуться.
git rev-parse --abbrev-ref HEAD # например: main
git rev-parse --short HEAD # например: 0de883f
# 3. Переключиться на нужный тег. Сборка по тегу даёт точно код этой версии.
git checkout v1.0.0
# 4. Собрать всё. VERSION и COMMIT будут вычислены из тега автоматически.
make release
# 5. Проверить, что в бинаре именно та версия.
./bin/linux_amd64/iptvc version # ожидаем: iptvc v1.0.0
# 6. Вернуться туда, где были.
git checkout main # или: git checkout 0de883f
Пример: собрать по конкретному коммиту
git checkout 0de883f
make release
git checkout main
Сборка в отдельной worktree (рекомендуется)
Переключение ветки в основной рабочей копии неудобно: IDE перезагружает индекс, открытые файлы могут стать невалидными, локальные правки блокируют checkout. Лучше использовать git worktree — это отдельная директория с привязкой к конкретному коммиту, основная рабочая копия не трогается.
# 1. Создать временный worktree на теге v1.0.0.
git worktree add /tmp/iptvc-v1.0.0 v1.0.0
# 2. Собрать там.
cd /tmp/iptvc-v1.0.0
make release
# 3. Убедиться, что бинарь содержит нужную версию.
./bin/linux_amd64/iptvc version # ожидаем: iptvc v1.0.0
# 4. Убрать worktree, когда он больше не нужен.
cd /path/to/main/repo
git worktree remove /tmp/iptvc-v1.0.0
Этот способ безопаснее git checkout: основная рабочая копия и все незакоммиченные изменения остаются нетронутыми.
Проверка, что собрано то, что нужно
После сборки в бинаре зашиты app.VERSION и app.COMMIT, которые выводятся командой version:
./bin/linux_amd64/iptvc version
# iptvc v1.0.0
Если версия не совпадает с ожидаемой — значит, рабочая копия была не на том коммите. Перепроверьте git log -1 --oneline в каталоге, из которого запускался make release.
Частые ошибки
- "build failed: COPY failed: uncommitted changes" — забыли
git status.COPY . .в Dockerfile включает только файлы, отслеживаемые git'ом, но локальные изменения вDockerfile/go.modи т.п. могут запутать. Всегда делайтеgit statusперед сборкой чужой версии. - "Permission denied" в
bin/— каталогbin/остался от предыдущей попытки с--output=localили от работы под другим пользователем. Решение:make clear(илиrm -rf bin). - Бинарь собран, но версия "dev"/"unknown" — скорее всего, вы в свежем клоне без тегов. Выполните
git fetch --tagsи повторитеgit checkout v1.0.0.
Перед запуском приложения для конфигурации обычно следует скопировать .env.example в .env, а config.yml.example — в config.yml, после чего адаптировать значения под окружение. Не добавляйте реальные пароли, токены или локальные URL в Git.
Docker
Для контейнерного окружения используется файл compose.yml, а не устаревшее имя docker-compose.yml.
Ожидаемые локальные файлы для сервиса iptvc:
playlists.iniмонтируется в/app/playlists.ini.channels.jsonмонтируется в/app/channels.json.config.ymlмонтируется в/app/config.yml..envпередаётся черезenv_file.
Основные команды:
# Собрать и запустить сервисы в фоне
docker compose up -d --build
# Посмотреть логи приложения
docker compose logs -f iptvc
# Остановить окружение
docker compose down
В compose-окружение входят:
iptvc— веб-интерфейс и фоновая проверка плейлистов.cache— хранилище результатов проверки.docs— отдельный сервис документации, если его контекст доступен в окружении.
Обратите внимание: текущий compose.yml ссылается на контексты ./iptvc и ./docs, поэтому запуск из каталога, содержащего только этот репозиторий, может потребовать внешней структуры проекта или корректировки контекстов.
Конфигурация
Поддерживаются config.yml, .env и CLI-флаги. CLI-флаги имеют наивысший приоритет только при явной передаче.
Источники правды
Единственными источниками правды для значений по умолчанию являются config.yml.example и .env.example. Значения, встроенные в код (app/config/config.go → defaults(), validate()), и дефолты CLI-флагов (cmd/flags.go, cmd/root.go, cmd/serve.go) обязаны полностью совпадать с этими файлами.
Порядок внесения изменений в конфигурацию:
- Сначала — правки в
config.yml.exampleи.env.example. - Затем — правки в коде:
app/config/config.go(defaults(), константы,validate()),cmd/flags.go,cmd/root.go,cmd/serve.go. - Затем — обновление тестов (
app/config/config_test.go,cmd/flags_test.go). - Затем — обновление документации (
README.md,docs/content/...).
При рефакторинге и работе с документацией сверяйтесь в первую очередь с config.yml.example и .env.example, а не с кодом или тестами. Если обнаружено расхождение между example-файлами и кодом — example-файлы считаются эталоном, код приводится к ним.
Ключевые группы настроек:
app— часовой пояс, режим отладки, уровень журнала и пути кplaylists.iniиchannels.json.server/site— адрес и порт веб-сервера, базовый URL, размер страницы, ссылки сайта и заголовок.check.playlists— User-Agent, тайм-ауты, задержки и параллелизм проверки плейлистов.check.channels— User-Agent, тайм-аут, размер диапазона байтов, задержки и параллелизм проверки каналов.cache— включение кеша, адрес подключения, база и TTL.
Значения задержек и некоторых параметров могут задаваться как числом или диапазоном [min, max]. User-Agent может быть строкой или массивом строк; при массиве выбирается случайное значение.
Веб-команда поддерживает как минимум следующие сценарии:
# Сервер без фоновой проверки
./iptvc serve -i playlists.ini -p 8800
# Сервер с бесконечной фоновой проверкой каждые 60 секунд
./iptvc serve --check --repeat 0 --playlists-all-cooldown 60
Основные HTTP-маршруты описаны в README: /, /page/{N}, /{code}, /{code}/details, /api/playlists/{code}, /api/version, /api/health и /api/stats.
Тестирование
Тесты находятся рядом с тестируемым кодом и используют стандартный пакет testing. Сейчас явно присутствуют тесты CLI-флагов в cmd/flags_test.go; они проверяют применение переопределений приложения, кеша и параметров проверки.
Перед изменением CLI или конфигурации запускайте:
go test ./...
go vet ./...
При обновлении конфигурационных структур синхронно проверяйте config.yml.example, .env.example, README.md и документацию в docs/content/common/config/config.md, docs/content/iptvc/commands/check.md, docs/content/iptvc/commands/serve.md и связанных страницах. См. также раздел «Источники правды» выше — правки начинаются с example-файлов.
При добавлении флага желательно добавить тесты на:
- значение по умолчанию без флага;
- явное включение и выключение boolean-флага;
- переопределение значения из конфигурации;
- корректный разбор чисел, диапазонов и списков;
- взаимодействие с приоритетом
config.yml, окружения и CLI.
Отдельных интеграционных тестов веб-сервера, кеша и сетевой проверки плейлистов в просмотренных файлах не обнаружено. Такие тесты требуют изолированных фикстур и не должны зависеть от случайных внешних IPTV-ресурсов.
Стиль разработки
- Соблюдайте стандартный стиль Go и форматируйте изменённые Go-файлы через
gofmt. - Используйте имена пакетов и экспортируемых сущностей в соответствии с идиомами Go.
- Сохраняйте существующие заголовки лицензии в файлах, где они уже присутствуют.
- Комментарии к экспортируемым типам и функциям должны объяснять их назначение.
- Не добавляйте секреты, реальные данные доступа к кешу и рабочие плейлисты в репозиторий.
- Для ошибок и сетевых операций сохраняйте существующую практику явной обработки ошибок и логирования.
- Не меняйте формат CLI, конфигурации или API-маршрутов без обновления README и соответствующих тестов.
- При работе с конфигурацией учитывайте различие между отсутствующим CLI-флагом и флагом, переданным явно: в
cmd/serve.goэто используется для корректного переопределения порта и хоста. - Избегайте сетевых запросов и зависимости от внешних сервисов в модульных тестах.
Важные ограничения и наблюдения
channels.json,playlists.ini,config.ymlи.envмогут быть локальными входными данными; проверяйте их наличие перед запуском сценариев из документации.- Кеш включён по умолчанию в
config.yml.exampleи.env.example; compose-окружение запускает кеш и передаёт настройки через.env. - Бинарные файлы и архивы сборки создаются в
bin/и не должны вручную добавляться в исходный код. - README указывает минимальную версию Go 1.23.6; Dockerfile использует
alpine:3.22.5и не собирает Go-код внутри контейнера. - При обновлении конфигурационных структур синхронно проверяйте
config.yml.example,.env.example, README и тесты CLI-флагов. Example-файлы — источники правды (см. раздел «Источники правды»).