Files
iptvc/AGENTS.md
T
2026-08-03 17:57:21 +08:00

26 KiB
Raw Blame History

Инструкции для работы с репозиторием

Обзор проекта

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.

Архитектура и поток выполнения

  1. main.go вызывает cmd.Execute().
  2. cmd/root.go регистрирует глобальные флаги и дочерние Cobra-команды.
  3. Команда check инициализирует приложение, применяет CLI-переопределения, подключает кеш, получает плейлисты и запускает проверку.
  4. Команда serve поднимает веб-сервер и при необходимости запускает фоновую проверку через флаг --check или настройку check.startOnServe.
  5. Конфигурация загружается со следующим приоритетом: встроенные значения по умолчанию, config.yml, переменные окружения и явно переданные CLI-флаги.
  6. Результаты проверки могут сохраняться в кеш и отображаться веб-сервером. При недоступном кеше веб-интерфейс показывает неизвестный статус.

Не следует помещать бизнес-логику в 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.godefaults(), validate()), и дефолты CLI-флагов (cmd/flags.go, cmd/root.go, cmd/serve.go) обязаны полностью совпадать с этими файлами.

Порядок внесения изменений в конфигурацию:

  1. Сначала — правки в config.yml.example и .env.example.
  2. Затем — правки в коде: app/config/config.go (defaults(), константы, validate()), cmd/flags.go, cmd/root.go, cmd/serve.go.
  3. Затем — обновление тестов (app/config/config_test.go, cmd/flags_test.go).
  4. Затем — обновление документации (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-файлы — источники правды (см. раздел «Источники правды»).