wip1
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
---
|
||||
title: check
|
||||
tags: [./iptvc]
|
||||
---
|
||||
|
||||
# Команда `check`
|
||||
|
||||
Команда поддерживает множество аргументов для разных целей.
|
||||
|
||||
Они могут дополнять друг друга.
|
||||
|
||||
Порядок аргументов не имеет значения.
|
||||
|
||||
## `-i`, `--ini` { id=ini }
|
||||
|
||||
Указывает путь к локальному [ini-файлу](../../formats/playlists.md) с описанием плейлистов.
|
||||
|
||||
Можно указать только однажды.
|
||||
|
||||
Значение по умолчанию: `./playlists.ini`
|
||||
|
||||
Если файл не найден, проверка плейлистов будет доступна только по ссылкам ([`--url`](#url)) или из локальных файлов ([`--file`](#file)).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini
|
||||
```
|
||||
|
||||
## `-t`, `--tags` { id=tags }
|
||||
|
||||
Указывает путь к локальному [json-файлу](../../formats/channels.md) с описанием тегов каналов.
|
||||
|
||||
Можно указать только однажды.
|
||||
|
||||
Значение по умолчанию: `./channels.json`
|
||||
|
||||
Если файл не найден, то будет выведено предупреждение о том, что каналы не будут помечены тегами.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -t ~/tags.json
|
||||
```
|
||||
|
||||
## `-f`, `--file` { id=file }
|
||||
|
||||
Указывает путь к локальному файлу плейлиста `*.m3u`/`*.m3u8`.
|
||||
|
||||
Можно указать несколько разных.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -f playlist.m3u
|
||||
./iptvc check -f playlist1.m3u --file playlist2.m3u8
|
||||
./iptvc check --file /path/to/playlist.m3u
|
||||
```
|
||||
|
||||
## `-u`, `--url` { id=url }
|
||||
|
||||
Указывает URL удалённого плейлиста (поддерживаются протоколы http/https).
|
||||
|
||||
Можно указать несколько разных.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -u http://example.com/playlist.m3u
|
||||
./iptvc check -u https://site.com/playlist.m3u8 --url http://other.com/list.m3u
|
||||
```
|
||||
|
||||
## `-c`, `--code` { id=code }
|
||||
|
||||
Указывает код плейлиста из файла [playlists.ini](../../formats/playlists.md).
|
||||
|
||||
Можно указать несколько разных.
|
||||
|
||||
!!! warning "Работает только вместе с [`--ini`](#ini)."
|
||||
|
||||
Если не указан ни разу, то будут проверены все плейлисты, которые указаны в ini-файле.
|
||||
|
||||
Если используется кеширование, то проверенные плейлисты (результаты проверки которых ещё находятся в кеше) проверяться не будут.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini -c RU_BASIC --code MOVIE_PREMIUM
|
||||
```
|
||||
|
||||
## `--repeat` { id=repeat }
|
||||
|
||||
Указывает количество повторений (итераций) команды.
|
||||
|
||||
Значение по умолчанию: `1`
|
||||
|
||||
Если указано `0`, тогда:
|
||||
|
||||
* повторение будет бесконечным;
|
||||
|
||||
* если переданы [`--url`](#url), [`--file`](#file) или [`--code`](#code), то на каждой итерации будут проверяться только указанные плейлисты;
|
||||
|
||||
* если не переданы [`--url`](#url), [`--file`](#file) или [`--code`](#code), то на каждой итерации список плейлистов будет подготавливаться заново.
|
||||
Если при этом используется кеширование, то проверенные плейлисты (результаты проверки которых ещё находятся в кеше) проверяться не будут.
|
||||
|
||||
```shell title="Пример"
|
||||
# проверить 5 раз плейлисты с кодами xx и yy из my.ini
|
||||
./iptvc check -i ~/my.ini -c xx --code yy --repeat 5
|
||||
# бесконечно проверять все плейлисты из my.ini, без учёта проверенных
|
||||
./iptvc check -i ~/my.ini --repeat 0
|
||||
# бесконечно проверять плейлист из файла
|
||||
./iptvc check -f test.m3u --repeat 0
|
||||
```
|
||||
|
||||
## `--every` { id=every }
|
||||
|
||||
Указывает количество секунд между повторениями (итерациями) команды.
|
||||
|
||||
Значение по умолчанию: `5`
|
||||
|
||||
Если указано `0`, то задержки не будет.
|
||||
|
||||
```shell title="Пример"
|
||||
# проверить 5 раз плейлисты с кодами xx и yy из my.ini каждые 5 секунд
|
||||
./iptvc check -i ~/my.ini -c xx --code yy --repeat 5 --every 5
|
||||
# бесконечно проверять все плейлисты из my.ini, без учёта проверенных, каждый час
|
||||
./iptvc check -i ~/my.ini --repeat 0 --every 3600
|
||||
# бесконечно проверять плейлист из файла каждые 10 секунд
|
||||
./iptvc check -f test.m3u --repeat 0 --every 10
|
||||
```
|
||||
|
||||
## `-r`, `--random` { id=random }
|
||||
|
||||
Указывает максимальное количество случайных плейлистов из ini-файла для проверки.
|
||||
|
||||
!!! warning "Работает только вместе с [`--ini`](#ini)."
|
||||
|
||||
Если не указан ни разу, то будут проверены все плейлисты, которые указаны в ini-файле.
|
||||
|
||||
Если используется кеширование, то проверенные плейлисты (результаты проверки которых ещё находятся в кеше) проверяться не будут.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini -r 10
|
||||
```
|
||||
|
||||
## `-j`, `--json` { id=json }
|
||||
|
||||
Если указано, то подробные результаты проверки будут выводиться в формате JSON.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -f playlist.m3u --json
|
||||
```
|
||||
|
||||
## `-q`, `--quiet` { id=quiet }
|
||||
|
||||
Подавляет вывод всех логов.
|
||||
|
||||
!!! info "Не влияет на [`--json`](#json) (JSON-данные будут выведены в stdout), но перекрывает [`--verbose`](#verbose) (логов не будет вовсе, независимо от повышенной подробности)."
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --random 10 --quiet --json
|
||||
```
|
||||
|
||||
## `-v`, `--verbose` { id=verbose }
|
||||
|
||||
Включает подробное логирование.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check --random 10 --verbose
|
||||
```
|
||||
|
||||
## Глобальные флаги { id=global }
|
||||
|
||||
Эти флаги доступны для всех команд и переопределяют значения из `config.yml`.
|
||||
|
||||
### `--debug` { id=debug }
|
||||
|
||||
Включает режим отладки. Переопределяет `app.debug` из `config.yml` и переменную `APP_DEBUG`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --debug
|
||||
```
|
||||
|
||||
### `--log-level` { id=log-level }
|
||||
|
||||
Устанавливает уровень логирования. Переопределяет `app.log_level` из `config.yml`.
|
||||
|
||||
Доступные значения: `debug`, `info`, `warn`, `error`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --log-level debug
|
||||
```
|
||||
|
||||
## Флаги проверки плейлистов { id=check-playlists }
|
||||
|
||||
Эти флаги переопределяют параметры секции `check.playlists` из `config.yml`. Доступны для команд `check` и `serve`.
|
||||
|
||||
### `--playlists-timeout` { id=playlists-timeout }
|
||||
|
||||
Таймаут HTTP-запроса плейлиста в миллисекундах.
|
||||
|
||||
Переопределяет `check.playlists.timeout` (по умолчанию `10000`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-timeout 5000
|
||||
```
|
||||
|
||||
### `--playlists-all-cooldown` { id=playlists-all-cooldown }
|
||||
|
||||
Задержка в миллисекундах после проверки всех плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.all-cooldown` (по умолчанию `0`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-all-cooldown 10000
|
||||
```
|
||||
|
||||
### `--playlists-one-cooldown` { id=playlists-one-cooldown }
|
||||
|
||||
Задержка в миллисекундах после проверки каждого плейлиста.
|
||||
|
||||
Переопределяет `check.playlists.one-cooldown` (по умолчанию `0`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-one-cooldown 2000
|
||||
```
|
||||
|
||||
### `--playlists-max-routines` { id=playlists-max-routines }
|
||||
|
||||
Максимум одновременно проверяемых плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.max-routines` (по умолчанию `5`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-max-routines 10
|
||||
```
|
||||
|
||||
### `--playlists-per-routine` { id=playlists-per-routine }
|
||||
|
||||
Количество плейлистов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.playlists.per-routine` (по умолчанию `1`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-per-routine 3
|
||||
```
|
||||
|
||||
### `--playlists-user-agent` { id=playlists-user-agent }
|
||||
|
||||
User-Agent для HTTP-запросов плейлистов. Можно указать несколько — будет выбран случайный при каждом запросе.
|
||||
|
||||
Переопределяет `check.playlists.user-agent`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --playlists-user-agent "Mozilla/5.0" "curl/8.0"
|
||||
```
|
||||
|
||||
## Флаги проверки каналов { id=check-channels }
|
||||
|
||||
Эти флаги переопределяют параметры секции `check.channels` из `config.yml`. Доступны для команд `check` и `serve`.
|
||||
|
||||
### `--channels-timeout` { id=channels-timeout }
|
||||
|
||||
Таймаут HTTP-запроса канала в миллисекундах.
|
||||
|
||||
Переопределяет `check.channels.timeout` (по умолчанию `10000`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-timeout 8000
|
||||
```
|
||||
|
||||
### `--channels-byte-range` { id=channels-byte-range }
|
||||
|
||||
Объём данных в байтах для загрузки от сервера при проверке канала.
|
||||
|
||||
Переопределяет `check.channels.byte-range` (по умолчанию `512`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-byte-range 1024
|
||||
```
|
||||
|
||||
### `--channels-cooldown` { id=channels-cooldown }
|
||||
|
||||
Задержка в миллисекундах после проверки каждого канала.
|
||||
|
||||
Переопределяет `check.channels.cooldown` (по умолчанию `0`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-cooldown 100
|
||||
```
|
||||
|
||||
### `--channels-max-routines` { id=channels-max-routines }
|
||||
|
||||
Максимум одновременно проверяемых каналов.
|
||||
|
||||
Переопределяет `check.channels.max-routines` (по умолчанию `50`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-max-routines 100
|
||||
```
|
||||
|
||||
### `--channels-per-routine` { id=channels-per-routine }
|
||||
|
||||
Количество каналов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.channels.per-routine` (по умолчанию `10`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-per-routine 20
|
||||
```
|
||||
|
||||
### `--channels-user-agent` { id=channels-user-agent }
|
||||
|
||||
User-Agent для HTTP-запросов каналов. Можно указать несколько — будет выбран случайный при каждом запросе.
|
||||
|
||||
Переопределяет `check.channels.user-agent`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --channels-user-agent "Mozilla/5.0" "VLC/3.0"
|
||||
```
|
||||
|
||||
## Флаги кеша { id=cache-flags }
|
||||
|
||||
Эти флаги переопределяют параметры секции `cache` из `config.yml`. Доступны для команд `check` и `serve`.
|
||||
|
||||
### `--cache-enabled` { id=cache-enabled }
|
||||
|
||||
Включает кеширование результатов в KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.enabled` (по умолчанию `false`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled
|
||||
```
|
||||
|
||||
### `--cache-host` { id=cache-host }
|
||||
|
||||
Хост KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.host` (по умолчанию `localhost`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-host 192.168.1.10
|
||||
```
|
||||
|
||||
### `--cache-port` { id=cache-port }
|
||||
|
||||
Порт KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.port` (по умолчанию `6379`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-port 6380
|
||||
```
|
||||
|
||||
### `--cache-username` { id=cache-username }
|
||||
|
||||
Логин для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.username`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-username myuser
|
||||
```
|
||||
|
||||
### `--cache-password` { id=cache-password }
|
||||
|
||||
Пароль для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.password`.
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-password secret
|
||||
```
|
||||
|
||||
### `--cache-db` { id=cache-db }
|
||||
|
||||
Номер базы данных KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.db` (по умолчанию `0`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-db 2
|
||||
```
|
||||
|
||||
### `--cache-ttl` { id=cache-ttl }
|
||||
|
||||
TTL записей кеша в секундах.
|
||||
|
||||
Переопределяет `cache.ttl` (по умолчанию `1800`).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini --cache-enabled --cache-ttl 3600
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: help
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `help`
|
||||
|
||||
Для получения помощи о программе, нужно вызвать команду `help` или передать аргумент `-h` или `--help`.
|
||||
|
||||
Равнозначные команды:
|
||||
|
||||
```
|
||||
./iptvc help
|
||||
./iptvc --help
|
||||
./iptvc -h
|
||||
```
|
||||
|
||||
Вывод (может незначительно отличаться в разных версиях):
|
||||
|
||||
```
|
||||
Simple utility to check iptv playlists. Part of m3u.su project.
|
||||
Copyright (c) 2025, Антон Аксенов, MIT license.
|
||||
|
||||
Usage:
|
||||
iptvc [command]
|
||||
|
||||
Available Commands:
|
||||
check Check playlists
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
help Help about any command
|
||||
version Show version
|
||||
|
||||
Flags:
|
||||
-h, --help help for iptvc
|
||||
-v, --verbose enable additional output
|
||||
|
||||
Use "iptvc [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
Чтобы получить справку о конкретной команде, можно вызвать программу одним из способов:
|
||||
|
||||
```
|
||||
./iptvc help <КОМАНДА>
|
||||
./iptvc <КОМАНДА> --help
|
||||
./iptvc <КОМАНДА> -h
|
||||
```
|
||||
|
||||
Список команд указан в этом разделе.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
icon: octicons/terminal-24
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# :octicons-terminal-24: Справочник команд
|
||||
|
||||
* [`check`](check.md) — проверка плейлистов
|
||||
* [`serve`](serve.md) — запуск веб-интерфейса
|
||||
* [`version`](version.md) — получение версии и выход
|
||||
* [`help`](help.md) — получение справки о программе и выход
|
||||
|
||||
Каждая команда отвечает за конкретную операцию и имеет свои настройки (аргументы), которыми можно влиять на логику выполнения операции.
|
||||
|
||||
Также есть глобальные аргументы, которые доступны для всех команд:
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Описание |
|
||||
| ----------------- | ------ | ---------------------------- | ----------------------------------------------------- |
|
||||
| `--config` | string | — | Путь к файлу конфигурации (по умолчанию `config.yml`) |
|
||||
| `--debug` | bool | `app.debug` | Включить режим отладки |
|
||||
| `--log-level` | string | `app.log_level` | Уровень логирования: `debug`, `info`, `warn`, `error` |
|
||||
| `-v`, `--verbose` | bool | — | Подробное логирование |
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
---
|
||||
title: serve
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `serve`
|
||||
|
||||
Запускает встроенный веб-сервер для просмотра плейлистов и результатов их проверки в браузере.
|
||||
|
||||
```bash
|
||||
iptvc serve [flags]
|
||||
```
|
||||
|
||||
## Веб-сервер
|
||||
|
||||
<a id="port"></a>
|
||||
### `-p`, `--port`
|
||||
|
||||
Порт для веб-сервера.
|
||||
|
||||
Переопределяет `server.port` из `config.yml` и переменную `WEB_PORT`.
|
||||
|
||||
Если не указан, используется значение из `config.yml` (по умолчанию `8080`).
|
||||
|
||||
```bash
|
||||
iptvc serve -p 3000
|
||||
```
|
||||
|
||||
<a id="host"></a>
|
||||
### `--host`
|
||||
|
||||
Хост для привязки веб-сервера.
|
||||
|
||||
Переопределяет `server.host` из `config.yml` и переменную `WEB_HOST`.
|
||||
|
||||
Если не указан, используется значение из `config.yml` (по умолчанию — все интерфейсы).
|
||||
|
||||
```bash
|
||||
iptvc serve --host 127.0.0.1
|
||||
```
|
||||
|
||||
## Фоновая проверка
|
||||
|
||||
<a id="check"></a>
|
||||
### `--check`
|
||||
|
||||
Включает фоновую проверку плейлистов. По умолчанию выключена.
|
||||
|
||||
Без этого флага веб-сервер работает standalone — отображает данные из кеша (если включён) или статус `unknown` для всех плейлистов.
|
||||
|
||||
```bash
|
||||
iptvc serve --check
|
||||
```
|
||||
|
||||
При `--check` доступны следующие флаги:
|
||||
|
||||
<a id="ini"></a>
|
||||
### `-i`, `--ini`
|
||||
|
||||
Путь к локальному [ini-файлу](../../formats/playlists.md) с описанием плейлистов.
|
||||
|
||||
Значение по умолчанию: `./playlists.ini`
|
||||
|
||||
```bash
|
||||
iptvc serve --check -i ~/my.ini
|
||||
```
|
||||
|
||||
<a id="tags"></a>
|
||||
### `-t`, `--tags`
|
||||
|
||||
Путь к [json-файлу](../../formats/channels.md) с описанием тегов каналов.
|
||||
|
||||
Значение по умолчанию: `./channels.json`
|
||||
|
||||
```bash
|
||||
iptvc serve --check -t ~/tags.json
|
||||
```
|
||||
|
||||
<a id="every"></a>
|
||||
### `--every`
|
||||
|
||||
Интервал между циклами фоновой проверки в секундах.
|
||||
|
||||
Значение по умолчанию: `60`
|
||||
|
||||
```bash
|
||||
iptvc serve --check --every 120
|
||||
```
|
||||
|
||||
<a id="repeat"></a>
|
||||
### `--repeat`
|
||||
|
||||
Количество циклов фоновой проверки.
|
||||
|
||||
Значение по умолчанию: `0` (бесконечно)
|
||||
|
||||
```bash
|
||||
# проверить один раз и остановить фоновую проверку
|
||||
iptvc serve --check --repeat 1
|
||||
```
|
||||
|
||||
<a id="random"></a>
|
||||
### `-r`, `--random`
|
||||
|
||||
Максимальное количество случайных плейлистов из ini-файла для проверки.
|
||||
|
||||
```bash
|
||||
iptvc serve --check -r 10
|
||||
```
|
||||
|
||||
## Глобальные флаги
|
||||
|
||||
<a id="config"></a>
|
||||
### `--config`
|
||||
|
||||
Путь к файлу конфигурации `config.yml`.
|
||||
|
||||
Значение по умолчанию: `config.yml`
|
||||
|
||||
```bash
|
||||
iptvc serve --config /etc/iptvc/config.yml
|
||||
```
|
||||
|
||||
<a id="debug"></a>
|
||||
### `--debug`
|
||||
|
||||
Включает режим отладки. Переопределяет `app.debug` из `config.yml` и переменную `APP_DEBUG`.
|
||||
|
||||
```bash
|
||||
iptvc serve --debug
|
||||
```
|
||||
|
||||
<a id="log-level"></a>
|
||||
### `--log-level`
|
||||
|
||||
Устанавливает уровень логирования. Переопределяет `app.log_level` из `config.yml`.
|
||||
|
||||
Доступные значения: `debug`, `info`, `warn`, `error`.
|
||||
|
||||
```bash
|
||||
iptvc serve --log-level debug
|
||||
```
|
||||
|
||||
<a id="verbose"></a>
|
||||
### `-v`, `--verbose`
|
||||
|
||||
Включает подробное логирование.
|
||||
|
||||
## Флаги проверки плейлистов
|
||||
|
||||
Эти флаги переопределяют параметры секции `check.playlists` из `config.yml`. Доступны для команд `check` и `serve`. Имеют смысл только при включённой фоновой проверке (`--check` или `check.start-on-serve: true`).
|
||||
|
||||
<a id="playlists-timeout"></a>
|
||||
### `--playlists-timeout`
|
||||
|
||||
Таймаут HTTP-запроса плейлиста в миллисекундах.
|
||||
|
||||
Переопределяет `check.playlists.timeout` (по умолчанию `10000`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-timeout 5000
|
||||
```
|
||||
|
||||
<a id="playlists-all-cooldown"></a>
|
||||
### `--playlists-all-cooldown`
|
||||
|
||||
Задержка в миллисекундах после проверки всех плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.all-cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-all-cooldown 10000
|
||||
```
|
||||
|
||||
<a id="playlists-one-cooldown"></a>
|
||||
### `--playlists-one-cooldown`
|
||||
|
||||
Задержка в миллисекундах после проверки каждого плейлиста.
|
||||
|
||||
Переопределяет `check.playlists.one-cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-one-cooldown 2000
|
||||
```
|
||||
|
||||
<a id="playlists-max-routines"></a>
|
||||
### `--playlists-max-routines`
|
||||
|
||||
Максимум одновременно проверяемых плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.max-routines` (по умолчанию `5`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-max-routines 10
|
||||
```
|
||||
|
||||
<a id="playlists-per-routine"></a>
|
||||
### `--playlists-per-routine`
|
||||
|
||||
Количество плейлистов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.playlists.per-routine` (по умолчанию `1`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-per-routine 3
|
||||
```
|
||||
|
||||
<a id="playlists-user-agent"></a>
|
||||
### `--playlists-user-agent`
|
||||
|
||||
User-Agent для HTTP-запросов плейлистов. Можно указать несколько — будет выбран случайный при каждом запросе.
|
||||
|
||||
Переопределяет `check.playlists.user-agent`.
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-user-agent "Mozilla/5.0" "curl/8.0"
|
||||
```
|
||||
|
||||
## Флаги проверки каналов
|
||||
|
||||
Эти флаги переопределяют параметры секции `check.channels` из `config.yml`. Доступны для команд `check` и `serve`. Имеют смысл только при включённой фоновой проверке.
|
||||
|
||||
<a id="channels-timeout"></a>
|
||||
### `--channels-timeout`
|
||||
|
||||
Таймаут HTTP-запроса канала в миллисекундах.
|
||||
|
||||
Переопределяет `check.channels.timeout` (по умолчанию `10000`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-timeout 8000
|
||||
```
|
||||
|
||||
<a id="channels-byte-range"></a>
|
||||
### `--channels-byte-range`
|
||||
|
||||
Объём данных в байтах для загрузки от сервера при проверке канала.
|
||||
|
||||
Переопределяет `check.channels.byte-range` (по умолчанию `512`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-byte-range 1024
|
||||
```
|
||||
|
||||
<a id="channels-cooldown"></a>
|
||||
### `--channels-cooldown`
|
||||
|
||||
Задержка в миллисекундах после проверки каждого канала.
|
||||
|
||||
Переопределяет `check.channels.cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-cooldown 100
|
||||
```
|
||||
|
||||
<a id="channels-max-routines"></a>
|
||||
### `--channels-max-routines`
|
||||
|
||||
Максимум одновременно проверяемых каналов.
|
||||
|
||||
Переопределяет `check.channels.max-routines` (по умолчанию `50`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-max-routines 100
|
||||
```
|
||||
|
||||
<a id="channels-per-routine"></a>
|
||||
### `--channels-per-routine`
|
||||
|
||||
Количество каналов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.channels.per-routine` (по умолчанию `10`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-per-routine 20
|
||||
```
|
||||
|
||||
<a id="channels-user-agent"></a>
|
||||
### `--channels-user-agent`
|
||||
|
||||
User-Agent для HTTP-запросов каналов. Можно указать несколько — будет выбран случайный при каждом запросе.
|
||||
|
||||
Переопределяет `check.channels.user-agent`.
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-user-agent "Mozilla/5.0" "VLC/3.0"
|
||||
```
|
||||
|
||||
## Флаги кеша
|
||||
|
||||
Эти флаги переопределяют параметры секции `cache` из `config.yml`. Доступны для команд `check` и `serve`.
|
||||
|
||||
<a id="cache-enabled"></a>
|
||||
### `--cache-enabled`
|
||||
|
||||
Включает кеширование результатов в KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.enabled` (по умолчанию `false`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled
|
||||
```
|
||||
|
||||
<a id="cache-host"></a>
|
||||
### `--cache-host`
|
||||
|
||||
Хост KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.host` (по умолчанию `localhost`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-host 192.168.1.10
|
||||
```
|
||||
|
||||
<a id="cache-port"></a>
|
||||
### `--cache-port`
|
||||
|
||||
Порт KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.port` (по умолчанию `6379`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-port 6380
|
||||
```
|
||||
|
||||
<a id="cache-username"></a>
|
||||
### `--cache-username`
|
||||
|
||||
Логин для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.username`.
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-username myuser
|
||||
```
|
||||
|
||||
<a id="cache-password"></a>
|
||||
### `--cache-password`
|
||||
|
||||
Пароль для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.password`.
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-password secret
|
||||
```
|
||||
|
||||
<a id="cache-db"></a>
|
||||
### `--cache-db`
|
||||
|
||||
Номер базы данных KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.db` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-db 2
|
||||
```
|
||||
|
||||
<a id="cache-ttl"></a>
|
||||
### `--cache-ttl`
|
||||
|
||||
TTL записей кеша в секундах.
|
||||
|
||||
Переопределяет `cache.ttl` (по умолчанию `1800`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-ttl 3600
|
||||
```
|
||||
|
||||
## Примеры
|
||||
|
||||
```bash
|
||||
# просто веб-сервер без проверки
|
||||
iptvc serve
|
||||
|
||||
# веб-сервер с фоновой проверкой каждые 2 минуты
|
||||
iptvc serve --check --every 120
|
||||
|
||||
# веб-сервер на порту 3000 с проверкой 10 случайных плейлистов
|
||||
iptvc serve -p 3000 --check -r 10
|
||||
|
||||
# один цикл проверки, затем только веб-сервер
|
||||
iptvc serve --check --repeat 1 --every 0
|
||||
|
||||
# веб-сервер с кешем и фоновой проверкой, увеличенные лимиты параллелизма
|
||||
iptvc serve --check --cache-enabled \
|
||||
--playlists-max-routines 10 \
|
||||
--channels-max-routines 100
|
||||
|
||||
# веб-сервер с отладкой и кастомным user-agent
|
||||
iptvc serve --check --debug \
|
||||
--playlists-user-agent "Mozilla/5.0" \
|
||||
--channels-user-agent "VLC/3.0"
|
||||
```
|
||||
|
||||
## Веб-маршруты
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| --- | --- | --- |
|
||||
| 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: статистика по плейлистам и каналам |
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: version
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `version`
|
||||
|
||||
Выводит версию программы:
|
||||
|
||||
```bash
|
||||
./iptvc version
|
||||
```
|
||||
|
||||
Пример результата:
|
||||
|
||||
```
|
||||
iptvc v1.0.6
|
||||
```
|
||||
@@ -0,0 +1,436 @@
|
||||
---
|
||||
title: config.yml
|
||||
icon: material/file-cog
|
||||
tags: ["iptvc", "конфигурация"]
|
||||
---
|
||||
|
||||
# :material-file-cog: Конфигурация config.yml
|
||||
|
||||
Программа читает настройки из YAML-файла `config.yml` в корне проекта.
|
||||
Путь к файлу можно задать через глобальный флаг `--config`.
|
||||
|
||||
## Приоритет настроек
|
||||
|
||||
От низшего к высшему:
|
||||
|
||||
1. **Значения по умолчанию** — встроены в код;
|
||||
2. **`config.yml`** — YAML-файл;
|
||||
3. **Переменные окружения** — переопределяют `config.yml` (если заданы);
|
||||
4. **CLI-флаги** — переопределяют переменные окружения и `config.yml` (если заданы явно).
|
||||
|
||||
Файл `.env` загружается автоматически, переменные из него применяются как переменные окружения.
|
||||
|
||||
## Структура файла
|
||||
|
||||
```yaml
|
||||
app:
|
||||
timezone: GMT
|
||||
debug: false
|
||||
log_level: info
|
||||
playlists: ./playlists.ini
|
||||
tags: ./channels.json
|
||||
|
||||
server:
|
||||
host: localhost
|
||||
port: 8080
|
||||
|
||||
site:
|
||||
base-url: http://localhost:8080
|
||||
repo-url: https://git.axenov.dev/IPTV
|
||||
page-size: 0
|
||||
favicon:
|
||||
header:
|
||||
title: IPTV Checker
|
||||
navigation:
|
||||
- title: Документация
|
||||
url: /docs
|
||||
icon: document-text-outline
|
||||
- title: Telegram
|
||||
icon: paper-plane-outline
|
||||
children:
|
||||
- title: Канал
|
||||
url: https://t.me/iptv_aggregator
|
||||
icon: megaphone-outline
|
||||
footer-links:
|
||||
- title: Исходники
|
||||
url: https://git.axenov.dev/IPTV
|
||||
icon: code-slash-outline
|
||||
|
||||
check:
|
||||
start-on-serve: false
|
||||
playlists:
|
||||
user-agent:
|
||||
- Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||
timeout: 10000
|
||||
all-cooldown: 0
|
||||
one-cooldown: 0
|
||||
max-routines: 5
|
||||
per-routine: 1
|
||||
channels:
|
||||
user-agent: Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||
timeout: 10000
|
||||
byte-range: 512
|
||||
cooldown: 0
|
||||
max-routines: 50
|
||||
per-routine: 10
|
||||
|
||||
cache:
|
||||
enabled: false
|
||||
host: localhost
|
||||
port: 6379
|
||||
username:
|
||||
password:
|
||||
db: 0
|
||||
ttl: 1800
|
||||
```
|
||||
|
||||
## Секция `app`
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| ----------- | ------ | ----------------- | ---------------------- |
|
||||
| `timezone` | string | `GMT` | Часовой пояс |
|
||||
| `debug` | bool | `false` | Режим отладки |
|
||||
| `log_level` | string | `info` | Уровень логирования |
|
||||
| `playlists` | string | `./playlists.ini` | Путь к `playlists.ini` |
|
||||
| `tags` | string | `./channels.json` | Путь к `channels.json` |
|
||||
|
||||
## Секция `server`
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| -------- | ------ | ------------ | ----------------- |
|
||||
| `host` | string | (пусто) | Хост для привязки |
|
||||
| `port` | uint | `8080` | Порт веб-сервера |
|
||||
|
||||
## Секция `site`
|
||||
|
||||
Настройки сайта: ссылки, заголовок, навигация, пагинация.
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| ----------- | ------ | ----------------------------- | ----------------------------------- |
|
||||
| `base-url` | string | `http://localhost:8080` | Базовый URL для формирования ссылок |
|
||||
| `repo-url` | string | `https://git.axenov.dev/IPTV` | Ссылка на репозиторий |
|
||||
| `page-size` | uint | `0` | Размер страницы (0 — без пагинации) |
|
||||
| `favicon` | string | (пусто) | Путь к иконке сайта |
|
||||
|
||||
### `site.header`
|
||||
|
||||
Настройки шапки сайта.
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| ------------ | ------ | -------------- | -------------------------------------- |
|
||||
| `title` | string | `IPTV Checker` | Заголовок сайта (в navbar и `<title>`) |
|
||||
| `navigation` | [Link] | (см. ниже) | Ссылки в шапке сайта |
|
||||
|
||||
### `site.footer-links`
|
||||
|
||||
Ссылки в подвале сайта. Массив элементов `Link`.
|
||||
|
||||
### Тип `Link`
|
||||
|
||||
Элемент навигации или подвала. Если задано `children`, рендерится как выпадающее меню.
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| ---------- | ------ | ----------------------------------------------------------- |
|
||||
| `title` | string | Текст ссылки |
|
||||
| `url` | string | URL ссылки (можно опустить, если есть `children`) |
|
||||
| `icon` | string | Имя иконки |
|
||||
| `children` | [Link] | Дочерние ссылки (выпадающее меню, один уровень вложенности) |
|
||||
|
||||
--8<-- "ionicons-name.md"
|
||||
|
||||
Пример:
|
||||
|
||||
```yaml
|
||||
site:
|
||||
header:
|
||||
navigation:
|
||||
- title: Документация
|
||||
url: /docs
|
||||
icon: document-text-outline
|
||||
- title: Telegram
|
||||
icon: paper-plane-outline
|
||||
children:
|
||||
- title: Канал
|
||||
url: https://t.me/iptv_aggregator
|
||||
icon: megaphone-outline
|
||||
- title: Чат
|
||||
url: https://t.me/iptv_aggregator_chat
|
||||
icon: chatbubbles-outline
|
||||
footer-links:
|
||||
- title: Исходники
|
||||
url: https://git.axenov.dev/IPTV
|
||||
icon: code-slash-outline
|
||||
- title: axenov.dev
|
||||
url: https://axenov.dev
|
||||
icon: person-outline
|
||||
```
|
||||
|
||||
## Секция `check`
|
||||
|
||||
Параметры проверки плейлистов и каналов. Поддерживаются скаляры и массивы.
|
||||
|
||||
### `check.start-on-serve`
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| ---------------- | ---- | ------------ | ---------------------------------------------------------- |
|
||||
| `start-on-serve` | bool | `false` | Запустить фоновую проверку при `serve` без флага `--check` |
|
||||
|
||||
### Типы значений
|
||||
|
||||
!!! info "timeout, max-routines, per-routine, byte-range"
|
||||
Эти параметры — всегда целые числа, не массивы.
|
||||
|
||||
!!! info "cooldown (all-cooldown, one-cooldown, channels.cooldown)"
|
||||
Эти параметры могут быть заданы:
|
||||
|
||||
- **скаляром** — фиксированное значение, например `all-cooldown: 10`;
|
||||
- **массивом `[min, max]`** — случайное значение в диапазоне при каждой проверке, например `all-cooldown: [5, 15]`.
|
||||
|
||||
!!! info "user-agent"
|
||||
Параметр `user-agent` может быть задан:
|
||||
|
||||
- **строкой** — используется всегда одно значение;
|
||||
- **массивом строк** — случайный выбор при каждом запросе.
|
||||
|
||||
!!! info "byte-range"
|
||||
Параметр `byte-range` — всегда целое число (не массив).
|
||||
|
||||
### `check.playlists`
|
||||
|
||||
Параметры проверки плейлистов (загрузка m3u-файлов по URL или из ФС).
|
||||
|
||||
| Параметр | Тип | По умолчанию | Единица | Описание |
|
||||
| -------------- | ------------------ | ----------------- | ------- | ------------------------------------------------ |
|
||||
| `user-agent` | string \| string[] | `Mozilla/5.0 ...` | — | User-Agent для HTTP-запросов |
|
||||
| `timeout` | int | `10000` | мс | Таймаут запроса плейлиста |
|
||||
| `all-cooldown` | int \| int[] | `0` | мс | Задержка после проверки всех плейлистов |
|
||||
| `one-cooldown` | int \| int[] | `0` | мс | Задержка после проверки каждого плейлиста |
|
||||
| `max-routines` | int | `5` | шт | Максимум одновременно проверяемых плейлистов |
|
||||
| `per-routine` | int | `1` | шт | Количество плейлистов на одну процедуру проверки |
|
||||
|
||||
### `check.channels`
|
||||
|
||||
Параметры проверки каналов внутри плейлиста.
|
||||
|
||||
| Параметр | Тип | По умолчанию | Единица | Описание |
|
||||
| -------------- | ------------------ | ----------------- | ------- | --------------------------------------------- |
|
||||
| `user-agent` | string \| string[] | `Mozilla/5.0 ...` | — | User-Agent для HTTP-запросов |
|
||||
| `timeout` | int | `10000` | мс | Таймаут запроса канала |
|
||||
| `byte-range` | int | `512` | байт | Объём данных для загрузки от сервера |
|
||||
| `cooldown` | int \| int[] | `0` | мс | Задержка после проверки каждого канала |
|
||||
| `max-routines` | int | `50` | шт | Максимум одновременно проверяемых каналов |
|
||||
| `per-routine` | int | `10` | шт | Количество каналов на одну процедуру проверки |
|
||||
|
||||
## Секция `cache`
|
||||
|
||||
| Параметр | Тип | По умолчанию | Описание |
|
||||
| ---------- | ------ | ------------ | ---------------------------------- |
|
||||
| `enabled` | bool | `false` | Включить кеширование (KeyDB/Redis) |
|
||||
| `host` | string | `localhost` | Хост KeyDB/Redis |
|
||||
| `port` | uint | `6379` | Порт KeyDB/Redis |
|
||||
| `username` | string | (пусто) | Логин |
|
||||
| `password` | string | (пусто) | Пароль |
|
||||
| `db` | uint | `0` | Номер БД |
|
||||
| `ttl` | uint | `1800` | TTL записей (сек) |
|
||||
|
||||
## Валидация
|
||||
|
||||
При запуске конфигурация валидируется.
|
||||
Некорректные значения исправляются автоматически, каждое исправление логируется:
|
||||
|
||||
| Проверка | Действие |
|
||||
| ---------------------------------------------------- | --------------------------------------- |
|
||||
| `server.port` = 0 или > 65535 | сброс в `8080` |
|
||||
| `site.base-url` пусто | автогенерация `http://localhost:{port}` |
|
||||
| `cache.host` пусто (если cache включён) | `localhost` |
|
||||
| `cache.port` = 0 (если cache включён) | `6379` |
|
||||
| `cache.ttl` = 0 (если cache включён) | `1800` |
|
||||
| `check.playlists.timeout` <= 0 | `10000` |
|
||||
| `check.channels.timeout` <= 0 | `10000` |
|
||||
| `check.*.cooldown` — `min > max` | swap |
|
||||
| `check.*.cooldown` — выход за границы `[0, 3600000]` | clamp |
|
||||
| `check.playlists.max-routines` < 1 | `5` |
|
||||
| `check.channels.max-routines` < 1 | `50` |
|
||||
| `check.playlists.per-routine` < 1 | `1` |
|
||||
| `check.channels.per-routine` < 1 | `10` |
|
||||
| `check.channels.byte-range` <= 0 | `512` |
|
||||
| `check.*.user-agent` пусто | дефолтный User-Agent |
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
Переменные окружения переопределяют значения из `config.yml`.
|
||||
|
||||
### Приложение
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| --------------- | ---------------------------- |
|
||||
| `APP_DEBUG` | `app.debug` |
|
||||
| `APP_LOG_LEVEL` | `app.log_level` |
|
||||
| `APP_TIMEZONE` | `app.timezone` |
|
||||
| `APP_PLAYLISTS` | `app.playlists` |
|
||||
| `APP_TAGS` | `app.tags` |
|
||||
|
||||
### Веб-сервер и сайт
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| -------------- | ---------------------------- |
|
||||
| `WEB_PORT` | `server.port` |
|
||||
| `WEB_HOST` | `server.host` |
|
||||
| `APP_URL` | `site.base-url` |
|
||||
| `PAGE_SIZE` | `site.page-size` |
|
||||
| `REPO_URL` | `site.repo-url` |
|
||||
| `SITE_FAVICON` | `site.favicon` |
|
||||
| `APP_TITLE` | `site.header.title` |
|
||||
|
||||
### Проверка
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| ---------------------- | ---------------------------- |
|
||||
| `CHECK_START_ON_SERVE` | `check.start-on-serve` |
|
||||
|
||||
#### `check.playlists`
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| ---------------------------------- | --------------------------------------------------- |
|
||||
| `CHECK_PLAYLISTS_TIMEOUT` | `check.playlists.timeout` |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN` | `check.playlists.all-cooldown` (скаляр) |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN_MIN` | `check.playlists.all-cooldown` (минимум диапазона) |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN_MAX` | `check.playlists.all-cooldown` (максимум диапазона) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN` | `check.playlists.one-cooldown` (скаляр) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN_MIN` | `check.playlists.one-cooldown` (минимум диапазона) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN_MAX` | `check.playlists.one-cooldown` (максимум диапазона) |
|
||||
| `CHECK_PLAYLISTS_MAX_ROUTINES` | `check.playlists.max-routines` |
|
||||
| `CHECK_PLAYLISTS_PER_ROUTINE` | `check.playlists.per-routine` |
|
||||
| `CHECK_PLAYLISTS_USER_AGENT_1` | `check.playlists.user-agent` (первый элемент) |
|
||||
| `CHECK_PLAYLISTS_USER_AGENT_2` | `check.playlists.user-agent` (второй элемент) |
|
||||
| `CHECK_PLAYLISTS_USER_AGENT_N` | `check.playlists.user-agent` (N-й элемент) |
|
||||
|
||||
#### `check.channels`
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| ----------------------------- | ---------------------------------------------- |
|
||||
| `CHECK_CHANNELS_TIMEOUT` | `check.channels.timeout` |
|
||||
| `CHECK_CHANNELS_BYTE_RANGE` | `check.channels.byte-range` |
|
||||
| `CHECK_CHANNELS_COOLDOWN` | `check.channels.cooldown` (скаляр) |
|
||||
| `CHECK_CHANNELS_COOLDOWN_MIN` | `check.channels.cooldown` (минимум диапазона) |
|
||||
| `CHECK_CHANNELS_COOLDOWN_MAX` | `check.channels.cooldown` (максимум диапазона) |
|
||||
| `CHECK_CHANNELS_MAX_ROUTINES` | `check.channels.max-routines` |
|
||||
| `CHECK_CHANNELS_PER_ROUTINE` | `check.channels.per-routine` |
|
||||
| `CHECK_CHANNELS_USER_AGENT_1` | `check.channels.user-agent` (первый элемент) |
|
||||
| `CHECK_CHANNELS_USER_AGENT_2` | `check.channels.user-agent` (второй элемент) |
|
||||
| `CHECK_CHANNELS_USER_AGENT_N` | `check.channels.user-agent` (N-й элемент) |
|
||||
|
||||
!!! info "Диапазоны cooldown через env"
|
||||
Если заданы обе переменные `_MIN` и `_MAX` — используется диапазон.
|
||||
Если задана только скалярная переменная (без `_MIN`/`_MAX`) — используется фиксированное значение.
|
||||
Если задана только одна из `_MIN`/`_MAX` — переменная игнорируется.
|
||||
|
||||
!!! info "Массивы user-agent через env"
|
||||
Переменные читаются последовательно: `_1`, `_2`, `_3`, …
|
||||
Первая отсутствующая переменная останавливает чтение.
|
||||
Пустые значения пропускаются.
|
||||
|
||||
### Кеш
|
||||
|
||||
| Переменная | Соответствует в `config.yml` |
|
||||
| ---------------- | ---------------------------- |
|
||||
| `CACHE_ENABLED` | `cache.enabled` |
|
||||
| `CACHE_HOST` | `cache.host` |
|
||||
| `CACHE_PORT` | `cache.port` |
|
||||
| `CACHE_USERNAME` | `cache.username` |
|
||||
| `CACHE_PASSWORD` | `cache.password` |
|
||||
| `CACHE_DB` | `cache.db` |
|
||||
| `CACHE_TTL` | `cache.ttl` |
|
||||
|
||||
## CLI-флаги
|
||||
|
||||
CLI-флаги имеют наивысший приоритет и переопределяют значения из `config.yml` и переменных окружения. Все флаги используют zero-value по умолчанию: переопределение срабатывает, только если флаг задан явно (через `cmd.Flags().Changed()`).
|
||||
|
||||
Порядок применения в обработчиках команд:
|
||||
|
||||
```
|
||||
app.Init() → defaults → config.yml → env → logger
|
||||
applyAppOverrides(cmd) → app.* через Changed()
|
||||
applyCacheOverrides(cmd) → cache.* через Changed()
|
||||
applyCheckOverrides(cmd) → check.* через Changed()
|
||||
app.InitCache() → подключение к KeyDB/Redis
|
||||
```
|
||||
|
||||
### Глобальные флаги
|
||||
|
||||
### Флаги путей
|
||||
|
||||
Доступны для `check` и `serve`.
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Описание |
|
||||
| -------------- | ------ | ---------------------------- | ---------------------- |
|
||||
| `-i`, `--ini` | string | `app.playlists` | Путь к `playlists.ini` |
|
||||
| `-t`, `--tags` | string | `app.tags` | Путь к `channels.json` |
|
||||
|
||||
### Флаги итерации
|
||||
|
||||
Доступны для `check` и `serve`.
|
||||
|
||||
| Флаг | Тип | По умолчанию | Описание |
|
||||
| ---------------- | ---- | ------------------------------ | --------------------------------------------- |
|
||||
| `-r`, `--random` | uint | `0` | Проверить N случайных плейлистов из ini-файла |
|
||||
| `--repeat` | uint | `1` (`check`) / `0` (`serve`) | Количество циклов (0 = бесконечно) |
|
||||
| `--every` | uint | `5` (`check`) / `60` (`serve`) | Секунд между циклами |
|
||||
|
||||
### Флаги проверки плейлистов
|
||||
|
||||
Доступны для `check` и `serve`. Переопределяют секцию `check.playlists`.
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Единица | Описание |
|
||||
| -------------------------- | -------- | ------------------------------ | ------- | -------------------------------- |
|
||||
| `--playlists-timeout` | int | `check.playlists.timeout` | мс | Таймаут запроса плейлиста |
|
||||
| `--playlists-all-cooldown` | int | `check.playlists.all-cooldown` | мс | Задержка после всех плейлистов |
|
||||
| `--playlists-one-cooldown` | int | `check.playlists.one-cooldown` | мс | Задержка после каждого плейлиста |
|
||||
| `--playlists-max-routines` | int | `check.playlists.max-routines` | шт | Максимум параллельных проверок |
|
||||
| `--playlists-per-routine` | int | `check.playlists.per-routine` | шт | Плейлистов на процедуру |
|
||||
| `--playlists-user-agent` | string[] | `check.playlists.user-agent` | — | User-Agent (можно несколько) |
|
||||
|
||||
### Флаги проверки каналов
|
||||
|
||||
Доступны для `check` и `serve`. Переопределяют секцию `check.channels`.
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Единица | Описание |
|
||||
| ------------------------- | -------- | ----------------------------- | ------- | ------------------------------ |
|
||||
| `--channels-timeout` | int | `check.channels.timeout` | мс | Таймаут запроса канала |
|
||||
| `--channels-byte-range` | int | `check.channels.byte-range` | байт | Объём данных от сервера |
|
||||
| `--channels-cooldown` | int | `check.channels.cooldown` | мс | Задержка после каждого канала |
|
||||
| `--channels-max-routines` | int | `check.channels.max-routines` | шт | Максимум параллельных проверок |
|
||||
| `--channels-per-routine` | int | `check.channels.per-routine` | шт | Каналов на процедуру |
|
||||
| `--channels-user-agent` | string[] | `check.channels.user-agent` | — | User-Agent (можно несколько) |
|
||||
|
||||
### Флаги кеша
|
||||
|
||||
Доступны для `check` и `serve`. Переопределяют секцию `cache`.
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Описание |
|
||||
| ------------------ | ------ | ---------------------------- | ----------------- |
|
||||
| `--cache-enabled` | bool | `cache.enabled` | Включить кеш |
|
||||
| `--cache-host` | string | `cache.host` | Хост KeyDB/Redis |
|
||||
| `--cache-port` | uint | `cache.port` | Порт KeyDB/Redis |
|
||||
| `--cache-username` | string | `cache.username` | Логин |
|
||||
| `--cache-password` | string | `cache.password` | Пароль |
|
||||
| `--cache-db` | uint | `cache.db` | Номер БД |
|
||||
| `--cache-ttl` | uint | `cache.ttl` | TTL записей (сек) |
|
||||
|
||||
### Флаги только для `serve`
|
||||
|
||||
| Флаг | Тип | Соответствует в `config.yml` | Описание |
|
||||
| -------------- | ------ | ---------------------------- | ------------------------- |
|
||||
| `-p`, `--port` | uint | `server.port` | Порт веб-сервера |
|
||||
| `--host` | string | `server.host` | Хост привязки |
|
||||
| `--check` | bool | — | Включить фоновую проверку |
|
||||
|
||||
### Флаги только для `check`
|
||||
|
||||
| Флаг | Тип | Описание |
|
||||
| --------------- | -------- | -------------------------- |
|
||||
| `-j`, `--json` | bool | Вывод результатов в JSON |
|
||||
| `-q`, `--quiet` | bool | Подавить логи |
|
||||
| `-f`, `--file` | string[] | Локальный m3u-файл |
|
||||
| `-u`, `--url` | string[] | URL удалённого плейлиста |
|
||||
| `-c`, `--code` | string[] | Код плейлиста из ini-файла |
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
icon: simple/dotenv
|
||||
tags: ["iptvc", "переменные окружения"]
|
||||
---
|
||||
|
||||
# :simple-dotenv: Переменные окружения
|
||||
|
||||
Переменные окружения переопределяют значения из [`config.yml`](config.md).
|
||||
Файл `.env` загружается автоматически при запуске.
|
||||
|
||||
Приоритет: **defaults → config.yml → env → CLI-флаги**.
|
||||
|
||||
## Приложение
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| ---------------- | ------ | ----------------------- | ----------------------------------------- |
|
||||
| `APP_DEBUG` | bool | `false` | Режим отладки |
|
||||
| `APP_LOG_LEVEL` | string | `info` | Уровень логирования (`debug`, `info`, `warn`, `error`) |
|
||||
| `APP_TIMEZONE` | string | `GMT` | Часовой пояс |
|
||||
| `APP_PLAYLISTS` | string | `./playlists.ini` | Путь к `playlists.ini` |
|
||||
| `APP_TAGS` | string | `./channels.json` | Путь к `channels.json` |
|
||||
|
||||
## Веб-сервер и сайт
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| ---------------- | ------ | ----------------------------- | ----------------------------------- |
|
||||
| `WEB_PORT` | uint | `8080` | Порт веб-сервера |
|
||||
| `WEB_HOST` | string | (пусто) | Хост для привязки |
|
||||
| `APP_URL` | string | `http://localhost:8080` | Базовый URL для ссылок |
|
||||
| `PAGE_SIZE` | uint | `0` | Размер страницы (0 — без пагинации) |
|
||||
| `REPO_URL` | string | `https://git.axenov.dev/IPTV` | Ссылка на репозиторий |
|
||||
| `SITE_FAVICON` | string | (пусто) | Путь к иконке сайта |
|
||||
| `APP_TITLE` | string | `IPTV Checker` | Заголовок сайта |
|
||||
|
||||
## Проверка
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| ----------------------- | --- | --------- | ------------------------------------------------------- |
|
||||
| `CHECK_START_ON_SERVE` | bool | `false` | Запустить фоновую проверку при `serve` без флага `--check` |
|
||||
|
||||
### `check.playlists`
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| --- | --- | --- | --- |
|
||||
| `CHECK_PLAYLISTS_TIMEOUT` | int | `10000` | Таймаут запроса плейлиста (мс) |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN` | int | `0` | Задержка после всех плейлистов (мс, скаляр) |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN_MIN` | int | `0` | Минимум задержки после всех плейлистов (мс) |
|
||||
| `CHECK_PLAYLISTS_ALL_COOLDOWN_MAX` | int | `0` | Максимум задержки после всех плейлистов (мс) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN` | int | `0` | Задержка после каждого плейлиста (мс, скаляр) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN_MIN` | int | `0` | Минимум задержки после каждого плейлиста (мс) |
|
||||
| `CHECK_PLAYLISTS_ONE_COOLDOWN_MAX` | int | `0` | Максимум задержки после каждого плейлиста (мс) |
|
||||
| `CHECK_PLAYLISTS_MAX_ROUTINES` | int | `5` | Максимум параллельных проверок плейлистов |
|
||||
| `CHECK_PLAYLISTS_PER_ROUTINE` | int | `1` | Плейлистов на процедуру |
|
||||
| `CHECK_PLAYLISTS_USER_AGENT_1` | string | `Mozilla/5.0 …` | Первый User-Agent для запросов плейлистов |
|
||||
| `CHECK_PLAYLISTS_USER_AGENT_2` | string | — | Второй User-Agent (и т.д.) |
|
||||
|
||||
### `check.channels`
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| --- | --- | --- | --- |
|
||||
| `CHECK_CHANNELS_TIMEOUT` | int | `10000` | Таймаут запроса канала (мс) |
|
||||
| `CHECK_CHANNELS_BYTE_RANGE` | int | `512` | Объём данных от сервера (байт) |
|
||||
| `CHECK_CHANNELS_COOLDOWN` | int | `0` | Задержка после каждого канала (мс, скаляр) |
|
||||
| `CHECK_CHANNELS_COOLDOWN_MIN` | int | `0` | Минимум задержки после каждого канала (мс) |
|
||||
| `CHECK_CHANNELS_COOLDOWN_MAX` | int | `0` | Максимум задержки после каждого канала (мс) |
|
||||
| `CHECK_CHANNELS_MAX_ROUTINES` | int | `50` | Максимум параллельных проверок каналов |
|
||||
| `CHECK_CHANNELS_PER_ROUTINE` | int | `10` | Каналов на процедуру |
|
||||
| `CHECK_CHANNELS_USER_AGENT_1` | string | `Mozilla/5.0 …` | Первый User-Agent для запросов каналов |
|
||||
| `CHECK_CHANNELS_USER_AGENT_2` | string | — | Второй User-Agent (и т.д.) |
|
||||
|
||||
## Кеширование
|
||||
|
||||
Кеш хранится в СУБД redis или keydb.
|
||||
|
||||
| Имя | Тип | Умолчание | Назначение |
|
||||
| ---------------- | ------ | ----------- | ---------------------------------- |
|
||||
| `CACHE_ENABLED` | bool | `false` | Включает кеширование |
|
||||
| `CACHE_HOST` | string | `localhost` | Имя хоста СУБД |
|
||||
| `CACHE_PORT` | uint | `6379` | Порт СУБД |
|
||||
| `CACHE_USERNAME` | string | (пусто) | Логин пользователя в СУБД |
|
||||
| `CACHE_PASSWORD` | string | (пусто) | Пароль пользователя в СУБД |
|
||||
| `CACHE_DB` | uint | `0` | Номер БД в СУБД для кеша |
|
||||
| `CACHE_TTL` | uint | `1800` | Время жизни ключей кеша в секундах |
|
||||
|
||||
## Правила
|
||||
|
||||
### Диапазоны cooldown
|
||||
|
||||
Поля `all-cooldown`, `one-cooldown` и `channels.cooldown` поддерживают скаляр и диапазон `[min, max]`.
|
||||
|
||||
Через env-переменные:
|
||||
|
||||
- Заданы **обе** `_MIN` и `_MAX` → диапазон (случайное значение при каждой проверке).
|
||||
- Задана только **скалярная** переменная (без суффикса) → фиксированное значение.
|
||||
- Задана только **одна** из `_MIN` / `_MAX` → переменная игнорируется.
|
||||
|
||||
```shell title="Скаляр"
|
||||
CHECK_PLAYLISTS_ALL_COOLDOWN=500
|
||||
```
|
||||
|
||||
```shell title="Диапазон"
|
||||
CHECK_PLAYLISTS_ALL_COOLDOWN_MIN=100
|
||||
CHECK_PLAYLISTS_ALL_COOLDOWN_MAX=2000
|
||||
```
|
||||
|
||||
### Массивы user-agent
|
||||
|
||||
Поля `user-agent` поддерживают массив строк. Через env задаются индексированными переменными `_1`, `_2`, `_3`, …
|
||||
|
||||
- Чтение останавливается на первой отсутствующей переменной.
|
||||
- Пустые значения пропускаются.
|
||||
|
||||
```shell title="Два User-Agent"
|
||||
CHECK_PLAYLISTS_USER_AGENT_1=Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||
CHECK_PLAYLISTS_USER_AGENT_2=curl/8.0
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
icon: material/upload-network
|
||||
---
|
||||
|
||||
# :material-upload-network: Развёртывание и доставка обновлений
|
||||
|
||||
!!! info "TODO"
|
||||
Скоро здесь появится полезная информация.
|
||||
Следи за обновлениями в канале [@iptv_aggregator](https://t.me/iptv_aggregator) или в [репозитории](https://git.axenov.dev/IPTV/docs).
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Компиляция
|
||||
icon: material/cog
|
||||
---
|
||||
|
||||
# Компиляция из исходного кода
|
||||
|
||||
Для компиляции потребуется golang v1.23.6 и выше.
|
||||
На версиях ниже не проверялось.
|
||||
|
||||
```bash
|
||||
git clone https://git.axenov.dev/IPTV/iptvc.git
|
||||
cd iptvc
|
||||
make linux
|
||||
# или make help для получения помощи по компиляции
|
||||
```
|
||||
|
||||
Поддерживается передача переменной `GOARCH`:
|
||||
|
||||
```shell
|
||||
make darwin GOARCH=arm64
|
||||
```
|
||||
|
||||
Скомпилированные файлы находятся в директории `bin/`.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Docker-образ
|
||||
icon: simple/docker
|
||||
---
|
||||
|
||||
# Построение Docker-образа
|
||||
|
||||
Предполагается выполнение в директории с исходниками.
|
||||
|
||||
```
|
||||
./build-docker-image.sh [<версия>]
|
||||
```
|
||||
|
||||
где `<версия>` — необязательный тег версии в формате `vX.Y.Z`.
|
||||
Если не указан, то будет взят последний.
|
||||
|
||||
Целевая платформа и архитектура меняется с помощью переменных `GOOS` и `GOARCH`:
|
||||
|
||||
```
|
||||
GOOS=darwin GOARCH=arm64 ./build-docker-image.sh [<версия>]
|
||||
```
|
||||
|
||||
Запуск:
|
||||
|
||||
```
|
||||
docker run --pull always --name iptvc git.axenov.dev/iptv/iptvc КОМАНДА [АРГУМЕНТЫ]
|
||||
```
|
||||
@@ -0,0 +1,284 @@
|
||||
# Песочница
|
||||
|
||||
|
||||
|
||||
## Мелочёвка
|
||||
|
||||
=== "Frontmatter"
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My Page
|
||||
description: Some page description
|
||||
icon: material/star
|
||||
tags: [tag1, tag2]
|
||||
hide: [navigation, toc, path]
|
||||
status: new
|
||||
#status: deprecated
|
||||
#status: beta
|
||||
---
|
||||
|
||||
# My Super-Duper Page
|
||||
|
||||
# Markdown content goes here
|
||||
```
|
||||
|
||||
=== "Бейджи"
|
||||
|
||||
<!-- md:version 8.5.0 --> <!-- md:default true --> <!-- md:flag experimental -->
|
||||
|
||||
=== "Тултипы"
|
||||
|
||||
:material-information-outline:{ title="текст подсказки" }
|
||||
|
||||
[Hover me 1](https://example.com "I'm first tooltip!")
|
||||
|
||||
[Hover me 2][example]
|
||||
|
||||
[example]: https://example.com "I'm second tooltip!"
|
||||
|
||||
=== "Кнопки"
|
||||
|
||||
[Серая кнопка](https://example.com/){ .md-button }
|
||||
|
||||
[Синяя кнопка](https://example.com/){ .md-button .md-button--primary }
|
||||
|
||||
[:fontawesome-solid-paper-plane: Кнопка серая с иконкой и подсказкой](https://example.com/){ .md-button title="текст подсказки 2" }
|
||||
|
||||
[:fontawesome-solid-paper-plane: Кнопка синяя с иконкой](https://example.com/){ .md-button .md-button--primary }
|
||||
|
||||
---
|
||||
|
||||
=== "Простой блок"
|
||||
|
||||
```python
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "С аннотациями"
|
||||
|
||||
```python
|
||||
def _render_icon(shortcode: str, md) -> str: #(1)!
|
||||
emoji_pattern = md.inlinePatterns.get("emoji") #(2)!
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode) #(3)!
|
||||
```
|
||||
|
||||
1. сигнатура функции
|
||||
2. инициализация переменной
|
||||
3. возврат результата
|
||||
|
||||
=== "С заголовком"
|
||||
|
||||
```python title="example.py"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "С нумерацией с 5"
|
||||
|
||||
```python linenums="5"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "С выделением"
|
||||
|
||||
```python linenums="1" hl_lines="2-5 8 9 22"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
try:
|
||||
emoji_pattern = md.inlinePatterns["emoji"]
|
||||
except KeyError:
|
||||
return escape(shortcode)
|
||||
|
||||
icon = emoji_pattern.emoji_index["emoji"].get(shortcode)
|
||||
if icon is None:
|
||||
return escape(shortcode)
|
||||
|
||||
element = emoji_pattern.generator(
|
||||
emoji_pattern.emoji_index["name"],
|
||||
shortcode,
|
||||
None,
|
||||
None,
|
||||
shortcode,
|
||||
"",
|
||||
icon.get("category", ""),
|
||||
emoji_pattern.options,
|
||||
md,
|
||||
)
|
||||
return tostring(element, encoding="unicode", method="html")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Врезки
|
||||
|
||||
=== "Полные"
|
||||
|
||||
!!! note "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! abstract "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! info "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! tip "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! success "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! question "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! warning "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! failure "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! danger "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! bug "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! example "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! quote "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Свёрнутые"
|
||||
|
||||
??? note "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? abstract "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? info "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? tip "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? success "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? question "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? warning "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? failure "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? danger "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? bug "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? example "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? quote "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Сворачиваемые"
|
||||
|
||||
???+ note "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ abstract "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ info "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ tip "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ success "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ question "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ warning "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ failure "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ danger "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ bug "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ example "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ quote "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Короткие"
|
||||
|
||||
!!! note
|
||||
Дефолтный заголовок
|
||||
|
||||
!!! abstract ""
|
||||
Пустой заголовок
|
||||
|
||||
!!! info "Пустое содержимое"
|
||||
|
||||
|
||||
---
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
icon: material/book-cog-outline
|
||||
---
|
||||
|
||||
# :material-book-cog-outline: Сборка документации
|
||||
|
||||
## Стилистика и правила оформления
|
||||
|
||||
Все исходники хранятся в директории `content/` в формате **Markdown** (формат файлов `.md`).
|
||||
|
||||
Структура проекта и его конфигурация описываются в файле `mkdocs.yml` в корне репозитория.
|
||||
|
||||
Структура исходных файлов документации и содержание должны быть согласованными.
|
||||
|
||||
Все ссылки на соседние страницы и изображения должны быть относительными.
|
||||
|
||||
**Каждое предложение должно быть на одной строке.**
|
||||
Это даёт более наглядную разницу (diff) в тексте при работе с git.
|
||||
|
||||
Абзацы и списки должны отделяться 1 пустой строкой до и после.
|
||||
|
||||
Допустимо использовать любые стилистические возможности темы **Material for MkDocs** и самого **mkdocs**, но не следует визуально перегружать текст.
|
||||
Документацию по ним см. по ссылкам ниже.
|
||||
|
||||
## Добавление изображений
|
||||
|
||||
**Все изображения хранятся только в директории `content/_assets/img/` и вложенных в неё.**
|
||||
|
||||
Общая суть такова:
|
||||
|
||||
* чем больше размеры, тем хуже должно быть качество;
|
||||
* чем меньше размеры, тем чётче должен быть текст.
|
||||
|
||||
Каждое изображение должно:
|
||||
|
||||
* быть сохранено в формате jpg;
|
||||
* иметь размер неболее 150 Кб;
|
||||
* быть сжатым с качеством 65-80% от исходного;
|
||||
* быть размером до 1500 px по наибольшей стороне.
|
||||
|
||||
Если на изображении есть текст, он должен оставаться различимым и читаемым.
|
||||
|
||||
Но если на изображении есть любые конфиденциальные данные и его невозможно кадрировать без потери смысла, то их необходимо скрыть.
|
||||
|
||||
Хорошей практикой будет использовать спойлеры для скрытия больших и/или идущих подряд нескольких изображений, например:
|
||||
|
||||
```
|
||||
Совершенно любой текст, lorem ipsum dolor sit amet.
|
||||
Совершенно любой текст, lorem ipsum dolor sit amet.
|
||||
|
||||
??? quote "В этом спойлере несколько больших картинок"
|
||||

|
||||

|
||||
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
```
|
||||
|
||||
Эти простые правила позволят поддерживать репозиторий достаточно компактным, а страницы делать комфортными для чтения, экономя трафик для мобильных устройств.
|
||||
|
||||
## Стек
|
||||
|
||||
* make
|
||||
* [docker](https://docker.com)
|
||||
* [mkdocs](https://www.mkdocs.org/)
|
||||
* [squidfunk/mkdocs-material](https://hub.docker.com/r/squidfunk/mkdocs-material)
|
||||
* <https://squidfunk.github.io/mkdocs-material>
|
||||
* <https://squidfunk.github.io/mkdocs-material/reference/admonitions/>
|
||||
* <https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/>
|
||||
|
||||
## Запуск mkdocs в контейнере
|
||||
|
||||
```
|
||||
make live
|
||||
```
|
||||
|
||||
Перегенерирует документацию на лету сразу после сохранения файлов.
|
||||
|
||||
Документацию в реальном времени можно просматривать по адресу [localhost:3000](http://localhost:3000).
|
||||
|
||||
## Генерация статического сайта
|
||||
|
||||
```
|
||||
make site
|
||||
```
|
||||
|
||||
Генерирует статические файлы, которую можно версионировать, хранить,деплоить отдельно или просматривать на ПК через браузер.
|
||||
|
||||
Готовый скомпилированный статический сайт с документацией находится в директории `site/`.
|
||||
|
||||
## Генерация docker-образа
|
||||
|
||||
```
|
||||
make image
|
||||
```
|
||||
|
||||
Собирает docker-образ на основе nginx, генерируя перед этим статический сайт.
|
||||
|
||||
Запустить контейнер из этого образа по адресу [localhost:3001](http://localhost:3001) можно командой:
|
||||
|
||||
```
|
||||
make run
|
||||
```
|
||||
@@ -0,0 +1,550 @@
|
||||
|
||||
|
||||
| Иконка | Код для вставки в текст | Код для вставки в frontmatter |
|
||||
| ------------------------------------------------ | -------------------------------------------------- | ------------------------------------------------ |
|
||||
| :vscode-account: | `:vscode-account:` | `vscode/account` |
|
||||
| :vscode-activate-breakpoints: | `:vscode-activate-breakpoints:` | `vscode/activate-breakpoints` |
|
||||
| :vscode-add: | `:vscode-add:` | `vscode/add` |
|
||||
| :vscode-add-small: | `:vscode-add-small:` | `vscode/add-small` |
|
||||
| :vscode-agent: | `:vscode-agent:` | `vscode/agent` |
|
||||
| :vscode-archive: | `:vscode-archive:` | `vscode/archive` |
|
||||
| :vscode-arrow-both: | `:vscode-arrow-both:` | `vscode/arrow-both` |
|
||||
| :vscode-arrow-circle-down: | `:vscode-arrow-circle-down:` | `vscode/arrow-circle-down` |
|
||||
| :vscode-arrow-circle-left: | `:vscode-arrow-circle-left:` | `vscode/arrow-circle-left` |
|
||||
| :vscode-arrow-circle-right: | `:vscode-arrow-circle-right:` | `vscode/arrow-circle-right` |
|
||||
| :vscode-arrow-circle-up: | `:vscode-arrow-circle-up:` | `vscode/arrow-circle-up` |
|
||||
| :vscode-arrow-down: | `:vscode-arrow-down:` | `vscode/arrow-down` |
|
||||
| :vscode-arrow-left: | `:vscode-arrow-left:` | `vscode/arrow-left` |
|
||||
| :vscode-arrow-right: | `:vscode-arrow-right:` | `vscode/arrow-right` |
|
||||
| :vscode-arrow-small-down: | `:vscode-arrow-small-down:` | `vscode/arrow-small-down` |
|
||||
| :vscode-arrow-small-left: | `:vscode-arrow-small-left:` | `vscode/arrow-small-left` |
|
||||
| :vscode-arrow-small-right: | `:vscode-arrow-small-right:` | `vscode/arrow-small-right` |
|
||||
| :vscode-arrow-small-up: | `:vscode-arrow-small-up:` | `vscode/arrow-small-up` |
|
||||
| :vscode-arrow-swap: | `:vscode-arrow-swap:` | `vscode/arrow-swap` |
|
||||
| :vscode-arrow-up: | `:vscode-arrow-up:` | `vscode/arrow-up` |
|
||||
| :vscode-ask: | `:vscode-ask:` | `vscode/ask` |
|
||||
| :vscode-attach: | `:vscode-attach:` | `vscode/attach` |
|
||||
| :vscode-azure: | `:vscode-azure:` | `vscode/azure` |
|
||||
| :vscode-azure-devops: | `:vscode-azure-devops:` | `vscode/azure-devops` |
|
||||
| :vscode-beaker: | `:vscode-beaker:` | `vscode/beaker` |
|
||||
| :vscode-beaker-stop: | `:vscode-beaker-stop:` | `vscode/beaker-stop` |
|
||||
| :vscode-bell: | `:vscode-bell:` | `vscode/bell` |
|
||||
| :vscode-bell-dot: | `:vscode-bell-dot:` | `vscode/bell-dot` |
|
||||
| :vscode-bell-slash: | `:vscode-bell-slash:` | `vscode/bell-slash` |
|
||||
| :vscode-bell-slash-dot: | `:vscode-bell-slash-dot:` | `vscode/bell-slash-dot` |
|
||||
| :vscode-blank: | `:vscode-blank:` | `vscode/blank` |
|
||||
| :vscode-bold: | `:vscode-bold:` | `vscode/bold` |
|
||||
| :vscode-book: | `:vscode-book:` | `vscode/book` |
|
||||
| :vscode-bookmark: | `:vscode-bookmark:` | `vscode/bookmark` |
|
||||
| :vscode-bracket-dot: | `:vscode-bracket-dot:` | `vscode/bracket-dot` |
|
||||
| :vscode-bracket-error: | `:vscode-bracket-error:` | `vscode/bracket-error` |
|
||||
| :vscode-briefcase: | `:vscode-briefcase:` | `vscode/briefcase` |
|
||||
| :vscode-broadcast: | `:vscode-broadcast:` | `vscode/broadcast` |
|
||||
| :vscode-browser: | `:vscode-browser:` | `vscode/browser` |
|
||||
| :vscode-bug: | `:vscode-bug:` | `vscode/bug` |
|
||||
| :vscode-build: | `:vscode-build:` | `vscode/build` |
|
||||
| :vscode-calendar: | `:vscode-calendar:` | `vscode/calendar` |
|
||||
| :vscode-call-incoming: | `:vscode-call-incoming:` | `vscode/call-incoming` |
|
||||
| :vscode-call-outgoing: | `:vscode-call-outgoing:` | `vscode/call-outgoing` |
|
||||
| :vscode-case-sensitive: | `:vscode-case-sensitive:` | `vscode/case-sensitive` |
|
||||
| :vscode-chat-export: | `:vscode-chat-export:` | `vscode/chat-export` |
|
||||
| :vscode-chat-import: | `:vscode-chat-import:` | `vscode/chat-import` |
|
||||
| :vscode-chat-sparkle: | `:vscode-chat-sparkle:` | `vscode/chat-sparkle` |
|
||||
| :vscode-chat-sparkle-error: | `:vscode-chat-sparkle-error:` | `vscode/chat-sparkle-error` |
|
||||
| :vscode-chat-sparkle-warning: | `:vscode-chat-sparkle-warning:` | `vscode/chat-sparkle-warning` |
|
||||
| :vscode-check: | `:vscode-check:` | `vscode/check` |
|
||||
| :vscode-check-all: | `:vscode-check-all:` | `vscode/check-all` |
|
||||
| :vscode-checklist: | `:vscode-checklist:` | `vscode/checklist` |
|
||||
| :vscode-chevron-down: | `:vscode-chevron-down:` | `vscode/chevron-down` |
|
||||
| :vscode-chevron-left: | `:vscode-chevron-left:` | `vscode/chevron-left` |
|
||||
| :vscode-chevron-right: | `:vscode-chevron-right:` | `vscode/chevron-right` |
|
||||
| :vscode-chevron-up: | `:vscode-chevron-up:` | `vscode/chevron-up` |
|
||||
| :vscode-chip: | `:vscode-chip:` | `vscode/chip` |
|
||||
| :vscode-chrome-close: | `:vscode-chrome-close:` | `vscode/chrome-close` |
|
||||
| :vscode-chrome-maximize: | `:vscode-chrome-maximize:` | `vscode/chrome-maximize` |
|
||||
| :vscode-chrome-minimize: | `:vscode-chrome-minimize:` | `vscode/chrome-minimize` |
|
||||
| :vscode-chrome-restore: | `:vscode-chrome-restore:` | `vscode/chrome-restore` |
|
||||
| :vscode-circle: | `:vscode-circle:` | `vscode/circle` |
|
||||
| :vscode-circle-filled: | `:vscode-circle-filled:` | `vscode/circle-filled` |
|
||||
| :vscode-circle-large: | `:vscode-circle-large:` | `vscode/circle-large` |
|
||||
| :vscode-circle-large-filled: | `:vscode-circle-large-filled:` | `vscode/circle-large-filled` |
|
||||
| :vscode-circle-slash: | `:vscode-circle-slash:` | `vscode/circle-slash` |
|
||||
| :vscode-circle-small: | `:vscode-circle-small:` | `vscode/circle-small` |
|
||||
| :vscode-circle-small-filled: | `:vscode-circle-small-filled:` | `vscode/circle-small-filled` |
|
||||
| :vscode-circuit-board: | `:vscode-circuit-board:` | `vscode/circuit-board` |
|
||||
| :vscode-claude: | `:vscode-claude:` | `vscode/claude` |
|
||||
| :vscode-clear-all: | `:vscode-clear-all:` | `vscode/clear-all` |
|
||||
| :vscode-clippy: | `:vscode-clippy:` | `vscode/clippy` |
|
||||
| :vscode-clockface: | `:vscode-clockface:` | `vscode/clockface` |
|
||||
| :vscode-close: | `:vscode-close:` | `vscode/close` |
|
||||
| :vscode-close-all: | `:vscode-close-all:` | `vscode/close-all` |
|
||||
| :vscode-cloud: | `:vscode-cloud:` | `vscode/cloud` |
|
||||
| :vscode-cloud-download: | `:vscode-cloud-download:` | `vscode/cloud-download` |
|
||||
| :vscode-cloud-small: | `:vscode-cloud-small:` | `vscode/cloud-small` |
|
||||
| :vscode-cloud-upload: | `:vscode-cloud-upload:` | `vscode/cloud-upload` |
|
||||
| :vscode-code: | `:vscode-code:` | `vscode/code` |
|
||||
| :vscode-code-oss: | `:vscode-code-oss:` | `vscode/code-oss` |
|
||||
| :vscode-code-review: | `:vscode-code-review:` | `vscode/code-review` |
|
||||
| :vscode-coffee: | `:vscode-coffee:` | `vscode/coffee` |
|
||||
| :vscode-collapse-all: | `:vscode-collapse-all:` | `vscode/collapse-all` |
|
||||
| :vscode-collection: | `:vscode-collection:` | `vscode/collection` |
|
||||
| :vscode-collection-small: | `:vscode-collection-small:` | `vscode/collection-small` |
|
||||
| :vscode-color-mode: | `:vscode-color-mode:` | `vscode/color-mode` |
|
||||
| :vscode-combine: | `:vscode-combine:` | `vscode/combine` |
|
||||
| :vscode-comment: | `:vscode-comment:` | `vscode/comment` |
|
||||
| :vscode-comment-discussion: | `:vscode-comment-discussion:` | `vscode/comment-discussion` |
|
||||
| :vscode-comment-discussion-quote: | `:vscode-comment-discussion-quote:` | `vscode/comment-discussion-quote` |
|
||||
| :vscode-comment-discussion-sparkle: | `:vscode-comment-discussion-sparkle:` | `vscode/comment-discussion-sparkle` |
|
||||
| :vscode-comment-draft: | `:vscode-comment-draft:` | `vscode/comment-draft` |
|
||||
| :vscode-comment-unresolved: | `:vscode-comment-unresolved:` | `vscode/comment-unresolved` |
|
||||
| :vscode-compass: | `:vscode-compass:` | `vscode/compass` |
|
||||
| :vscode-compass-active: | `:vscode-compass-active:` | `vscode/compass-active` |
|
||||
| :vscode-compass-dot: | `:vscode-compass-dot:` | `vscode/compass-dot` |
|
||||
| :vscode-copilot: | `:vscode-copilot:` | `vscode/copilot` |
|
||||
| :vscode-copilot-blocked: | `:vscode-copilot-blocked:` | `vscode/copilot-blocked` |
|
||||
| :vscode-copilot-error: | `:vscode-copilot-error:` | `vscode/copilot-error` |
|
||||
| :vscode-copilot-in-progress: | `:vscode-copilot-in-progress:` | `vscode/copilot-in-progress` |
|
||||
| :vscode-copilot-large: | `:vscode-copilot-large:` | `vscode/copilot-large` |
|
||||
| :vscode-copilot-not-connected: | `:vscode-copilot-not-connected:` | `vscode/copilot-not-connected` |
|
||||
| :vscode-copilot-snooze: | `:vscode-copilot-snooze:` | `vscode/copilot-snooze` |
|
||||
| :vscode-copilot-success: | `:vscode-copilot-success:` | `vscode/copilot-success` |
|
||||
| :vscode-copilot-unavailable: | `:vscode-copilot-unavailable:` | `vscode/copilot-unavailable` |
|
||||
| :vscode-copilot-warning: | `:vscode-copilot-warning:` | `vscode/copilot-warning` |
|
||||
| :vscode-copilot-warning-large: | `:vscode-copilot-warning-large:` | `vscode/copilot-warning-large` |
|
||||
| :vscode-copy: | `:vscode-copy:` | `vscode/copy` |
|
||||
| :vscode-coverage: | `:vscode-coverage:` | `vscode/coverage` |
|
||||
| :vscode-credit-card: | `:vscode-credit-card:` | `vscode/credit-card` |
|
||||
| :vscode-cursor: | `:vscode-cursor:` | `vscode/cursor` |
|
||||
| :vscode-dash: | `:vscode-dash:` | `vscode/dash` |
|
||||
| :vscode-dashboard: | `:vscode-dashboard:` | `vscode/dashboard` |
|
||||
| :vscode-database: | `:vscode-database:` | `vscode/database` |
|
||||
| :vscode-debug: | `:vscode-debug:` | `vscode/debug` |
|
||||
| :vscode-debug-all: | `:vscode-debug-all:` | `vscode/debug-all` |
|
||||
| :vscode-debug-alt: | `:vscode-debug-alt:` | `vscode/debug-alt` |
|
||||
| :vscode-debug-alt-small: | `:vscode-debug-alt-small:` | `vscode/debug-alt-small` |
|
||||
| :vscode-debug-breakpoint-conditional: | `:vscode-debug-breakpoint-conditional:` | `vscode/debug-breakpoint-conditional` |
|
||||
| :vscode-debug-breakpoint-conditional-unverified: | `:vscode-debug-breakpoint-conditional-unverified:` | `vscode/debug-breakpoint-conditional-unverified` |
|
||||
| :vscode-debug-breakpoint-data: | `:vscode-debug-breakpoint-data:` | `vscode/debug-breakpoint-data` |
|
||||
| :vscode-debug-breakpoint-data-unverified: | `:vscode-debug-breakpoint-data-unverified:` | `vscode/debug-breakpoint-data-unverified` |
|
||||
| :vscode-debug-breakpoint-function: | `:vscode-debug-breakpoint-function:` | `vscode/debug-breakpoint-function` |
|
||||
| :vscode-debug-breakpoint-function-unverified: | `:vscode-debug-breakpoint-function-unverified:` | `vscode/debug-breakpoint-function-unverified` |
|
||||
| :vscode-debug-breakpoint-log: | `:vscode-debug-breakpoint-log:` | `vscode/debug-breakpoint-log` |
|
||||
| :vscode-debug-breakpoint-log-unverified: | `:vscode-debug-breakpoint-log-unverified:` | `vscode/debug-breakpoint-log-unverified` |
|
||||
| :vscode-debug-breakpoint-unsupported: | `:vscode-debug-breakpoint-unsupported:` | `vscode/debug-breakpoint-unsupported` |
|
||||
| :vscode-debug-connected: | `:vscode-debug-connected:` | `vscode/debug-connected` |
|
||||
| :vscode-debug-console: | `:vscode-debug-console:` | `vscode/debug-console` |
|
||||
| :vscode-debug-continue: | `:vscode-debug-continue:` | `vscode/debug-continue` |
|
||||
| :vscode-debug-continue-small: | `:vscode-debug-continue-small:` | `vscode/debug-continue-small` |
|
||||
| :vscode-debug-coverage: | `:vscode-debug-coverage:` | `vscode/debug-coverage` |
|
||||
| :vscode-debug-disconnect: | `:vscode-debug-disconnect:` | `vscode/debug-disconnect` |
|
||||
| :vscode-debug-line-by-line: | `:vscode-debug-line-by-line:` | `vscode/debug-line-by-line` |
|
||||
| :vscode-debug-pause: | `:vscode-debug-pause:` | `vscode/debug-pause` |
|
||||
| :vscode-debug-rerun: | `:vscode-debug-rerun:` | `vscode/debug-rerun` |
|
||||
| :vscode-debug-restart: | `:vscode-debug-restart:` | `vscode/debug-restart` |
|
||||
| :vscode-debug-restart-frame: | `:vscode-debug-restart-frame:` | `vscode/debug-restart-frame` |
|
||||
| :vscode-debug-reverse-continue: | `:vscode-debug-reverse-continue:` | `vscode/debug-reverse-continue` |
|
||||
| :vscode-debug-stackframe: | `:vscode-debug-stackframe:` | `vscode/debug-stackframe` |
|
||||
| :vscode-debug-stackframe-active: | `:vscode-debug-stackframe-active:` | `vscode/debug-stackframe-active` |
|
||||
| :vscode-debug-start: | `:vscode-debug-start:` | `vscode/debug-start` |
|
||||
| :vscode-debug-step-back: | `:vscode-debug-step-back:` | `vscode/debug-step-back` |
|
||||
| :vscode-debug-step-into: | `:vscode-debug-step-into:` | `vscode/debug-step-into` |
|
||||
| :vscode-debug-step-out: | `:vscode-debug-step-out:` | `vscode/debug-step-out` |
|
||||
| :vscode-debug-step-over: | `:vscode-debug-step-over:` | `vscode/debug-step-over` |
|
||||
| :vscode-debug-stop: | `:vscode-debug-stop:` | `vscode/debug-stop` |
|
||||
| :vscode-desktop-download: | `:vscode-desktop-download:` | `vscode/desktop-download` |
|
||||
| :vscode-device-camera: | `:vscode-device-camera:` | `vscode/device-camera` |
|
||||
| :vscode-device-camera-video: | `:vscode-device-camera-video:` | `vscode/device-camera-video` |
|
||||
| :vscode-device-mobile: | `:vscode-device-mobile:` | `vscode/device-mobile` |
|
||||
| :vscode-diff: | `:vscode-diff:` | `vscode/diff` |
|
||||
| :vscode-diff-added: | `:vscode-diff-added:` | `vscode/diff-added` |
|
||||
| :vscode-diff-ignored: | `:vscode-diff-ignored:` | `vscode/diff-ignored` |
|
||||
| :vscode-diff-modified: | `:vscode-diff-modified:` | `vscode/diff-modified` |
|
||||
| :vscode-diff-multiple: | `:vscode-diff-multiple:` | `vscode/diff-multiple` |
|
||||
| :vscode-diff-removed: | `:vscode-diff-removed:` | `vscode/diff-removed` |
|
||||
| :vscode-diff-renamed: | `:vscode-diff-renamed:` | `vscode/diff-renamed` |
|
||||
| :vscode-diff-single: | `:vscode-diff-single:` | `vscode/diff-single` |
|
||||
| :vscode-discard: | `:vscode-discard:` | `vscode/discard` |
|
||||
| :vscode-download: | `:vscode-download:` | `vscode/download` |
|
||||
| :vscode-edit: | `:vscode-edit:` | `vscode/edit` |
|
||||
| :vscode-edit-code: | `:vscode-edit-code:` | `vscode/edit-code` |
|
||||
| :vscode-edit-session: | `:vscode-edit-session:` | `vscode/edit-session` |
|
||||
| :vscode-edit-sparkle: | `:vscode-edit-sparkle:` | `vscode/edit-sparkle` |
|
||||
| :vscode-editor-layout: | `:vscode-editor-layout:` | `vscode/editor-layout` |
|
||||
| :vscode-ellipsis: | `:vscode-ellipsis:` | `vscode/ellipsis` |
|
||||
| :vscode-empty-window: | `:vscode-empty-window:` | `vscode/empty-window` |
|
||||
| :vscode-eraser: | `:vscode-eraser:` | `vscode/eraser` |
|
||||
| :vscode-error: | `:vscode-error:` | `vscode/error` |
|
||||
| :vscode-error-small: | `:vscode-error-small:` | `vscode/error-small` |
|
||||
| :vscode-exclude: | `:vscode-exclude:` | `vscode/exclude` |
|
||||
| :vscode-expand-all: | `:vscode-expand-all:` | `vscode/expand-all` |
|
||||
| :vscode-export: | `:vscode-export:` | `vscode/export` |
|
||||
| :vscode-extensions: | `:vscode-extensions:` | `vscode/extensions` |
|
||||
| :vscode-extensions-large: | `:vscode-extensions-large:` | `vscode/extensions-large` |
|
||||
| :vscode-eye: | `:vscode-eye:` | `vscode/eye` |
|
||||
| :vscode-eye-closed: | `:vscode-eye-closed:` | `vscode/eye-closed` |
|
||||
| :vscode-feedback: | `:vscode-feedback:` | `vscode/feedback` |
|
||||
| :vscode-file: | `:vscode-file:` | `vscode/file` |
|
||||
| :vscode-file-binary: | `:vscode-file-binary:` | `vscode/file-binary` |
|
||||
| :vscode-file-code: | `:vscode-file-code:` | `vscode/file-code` |
|
||||
| :vscode-file-media: | `:vscode-file-media:` | `vscode/file-media` |
|
||||
| :vscode-file-pdf: | `:vscode-file-pdf:` | `vscode/file-pdf` |
|
||||
| :vscode-file-submodule: | `:vscode-file-submodule:` | `vscode/file-submodule` |
|
||||
| :vscode-file-symlink-directory: | `:vscode-file-symlink-directory:` | `vscode/file-symlink-directory` |
|
||||
| :vscode-file-symlink-file: | `:vscode-file-symlink-file:` | `vscode/file-symlink-file` |
|
||||
| :vscode-file-text: | `:vscode-file-text:` | `vscode/file-text` |
|
||||
| :vscode-file-zip: | `:vscode-file-zip:` | `vscode/file-zip` |
|
||||
| :vscode-files: | `:vscode-files:` | `vscode/files` |
|
||||
| :vscode-filter: | `:vscode-filter:` | `vscode/filter` |
|
||||
| :vscode-filter-filled: | `:vscode-filter-filled:` | `vscode/filter-filled` |
|
||||
| :vscode-flag: | `:vscode-flag:` | `vscode/flag` |
|
||||
| :vscode-flame: | `:vscode-flame:` | `vscode/flame` |
|
||||
| :vscode-fold: | `:vscode-fold:` | `vscode/fold` |
|
||||
| :vscode-fold-down: | `:vscode-fold-down:` | `vscode/fold-down` |
|
||||
| :vscode-fold-up: | `:vscode-fold-up:` | `vscode/fold-up` |
|
||||
| :vscode-folder: | `:vscode-folder:` | `vscode/folder` |
|
||||
| :vscode-folder-active: | `:vscode-folder-active:` | `vscode/folder-active` |
|
||||
| :vscode-folder-library: | `:vscode-folder-library:` | `vscode/folder-library` |
|
||||
| :vscode-folder-opened: | `:vscode-folder-opened:` | `vscode/folder-opened` |
|
||||
| :vscode-forward: | `:vscode-forward:` | `vscode/forward` |
|
||||
| :vscode-game: | `:vscode-game:` | `vscode/game` |
|
||||
| :vscode-gear: | `:vscode-gear:` | `vscode/gear` |
|
||||
| :vscode-gift: | `:vscode-gift:` | `vscode/gift` |
|
||||
| :vscode-gist: | `:vscode-gist:` | `vscode/gist` |
|
||||
| :vscode-gist-secret: | `:vscode-gist-secret:` | `vscode/gist-secret` |
|
||||
| :vscode-git-branch: | `:vscode-git-branch:` | `vscode/git-branch` |
|
||||
| :vscode-git-branch-changes: | `:vscode-git-branch-changes:` | `vscode/git-branch-changes` |
|
||||
| :vscode-git-branch-conflicts: | `:vscode-git-branch-conflicts:` | `vscode/git-branch-conflicts` |
|
||||
| :vscode-git-branch-staged-changes: | `:vscode-git-branch-staged-changes:` | `vscode/git-branch-staged-changes` |
|
||||
| :vscode-git-commit: | `:vscode-git-commit:` | `vscode/git-commit` |
|
||||
| :vscode-git-compare: | `:vscode-git-compare:` | `vscode/git-compare` |
|
||||
| :vscode-git-fetch: | `:vscode-git-fetch:` | `vscode/git-fetch` |
|
||||
| :vscode-git-merge: | `:vscode-git-merge:` | `vscode/git-merge` |
|
||||
| :vscode-git-pull-request: | `:vscode-git-pull-request:` | `vscode/git-pull-request` |
|
||||
| :vscode-git-pull-request-closed: | `:vscode-git-pull-request-closed:` | `vscode/git-pull-request-closed` |
|
||||
| :vscode-git-pull-request-create: | `:vscode-git-pull-request-create:` | `vscode/git-pull-request-create` |
|
||||
| :vscode-git-pull-request-done: | `:vscode-git-pull-request-done:` | `vscode/git-pull-request-done` |
|
||||
| :vscode-git-pull-request-draft: | `:vscode-git-pull-request-draft:` | `vscode/git-pull-request-draft` |
|
||||
| :vscode-git-pull-request-go-to-changes: | `:vscode-git-pull-request-go-to-changes:` | `vscode/git-pull-request-go-to-changes` |
|
||||
| :vscode-git-pull-request-new-changes: | `:vscode-git-pull-request-new-changes:` | `vscode/git-pull-request-new-changes` |
|
||||
| :vscode-git-stash: | `:vscode-git-stash:` | `vscode/git-stash` |
|
||||
| :vscode-git-stash-apply: | `:vscode-git-stash-apply:` | `vscode/git-stash-apply` |
|
||||
| :vscode-git-stash-pop: | `:vscode-git-stash-pop:` | `vscode/git-stash-pop` |
|
||||
| :vscode-github: | `:vscode-github:` | `vscode/github` |
|
||||
| :vscode-github-action: | `:vscode-github-action:` | `vscode/github-action` |
|
||||
| :vscode-github-alt: | `:vscode-github-alt:` | `vscode/github-alt` |
|
||||
| :vscode-github-inverted: | `:vscode-github-inverted:` | `vscode/github-inverted` |
|
||||
| :vscode-github-project: | `:vscode-github-project:` | `vscode/github-project` |
|
||||
| :vscode-globe: | `:vscode-globe:` | `vscode/globe` |
|
||||
| :vscode-go-to-editing-session: | `:vscode-go-to-editing-session:` | `vscode/go-to-editing-session` |
|
||||
| :vscode-go-to-file: | `:vscode-go-to-file:` | `vscode/go-to-file` |
|
||||
| :vscode-go-to-search: | `:vscode-go-to-search:` | `vscode/go-to-search` |
|
||||
| :vscode-grabber: | `:vscode-grabber:` | `vscode/grabber` |
|
||||
| :vscode-graph: | `:vscode-graph:` | `vscode/graph` |
|
||||
| :vscode-graph-left: | `:vscode-graph-left:` | `vscode/graph-left` |
|
||||
| :vscode-graph-line: | `:vscode-graph-line:` | `vscode/graph-line` |
|
||||
| :vscode-graph-scatter: | `:vscode-graph-scatter:` | `vscode/graph-scatter` |
|
||||
| :vscode-gripper: | `:vscode-gripper:` | `vscode/gripper` |
|
||||
| :vscode-group-by-ref-type: | `:vscode-group-by-ref-type:` | `vscode/group-by-ref-type` |
|
||||
| :vscode-heart: | `:vscode-heart:` | `vscode/heart` |
|
||||
| :vscode-heart-filled: | `:vscode-heart-filled:` | `vscode/heart-filled` |
|
||||
| :vscode-history: | `:vscode-history:` | `vscode/history` |
|
||||
| :vscode-home: | `:vscode-home:` | `vscode/home` |
|
||||
| :vscode-horizontal-rule: | `:vscode-horizontal-rule:` | `vscode/horizontal-rule` |
|
||||
| :vscode-hubot: | `:vscode-hubot:` | `vscode/hubot` |
|
||||
| :vscode-inbox: | `:vscode-inbox:` | `vscode/inbox` |
|
||||
| :vscode-indent: | `:vscode-indent:` | `vscode/indent` |
|
||||
| :vscode-index-zero: | `:vscode-index-zero:` | `vscode/index-zero` |
|
||||
| :vscode-info: | `:vscode-info:` | `vscode/info` |
|
||||
| :vscode-insert: | `:vscode-insert:` | `vscode/insert` |
|
||||
| :vscode-inspect: | `:vscode-inspect:` | `vscode/inspect` |
|
||||
| :vscode-issue-draft: | `:vscode-issue-draft:` | `vscode/issue-draft` |
|
||||
| :vscode-issue-reopened: | `:vscode-issue-reopened:` | `vscode/issue-reopened` |
|
||||
| :vscode-issues: | `:vscode-issues:` | `vscode/issues` |
|
||||
| :vscode-italic: | `:vscode-italic:` | `vscode/italic` |
|
||||
| :vscode-jersey: | `:vscode-jersey:` | `vscode/jersey` |
|
||||
| :vscode-json: | `:vscode-json:` | `vscode/json` |
|
||||
| :vscode-kebab-vertical: | `:vscode-kebab-vertical:` | `vscode/kebab-vertical` |
|
||||
| :vscode-key: | `:vscode-key:` | `vscode/key` |
|
||||
| :vscode-keyboard-tab: | `:vscode-keyboard-tab:` | `vscode/keyboard-tab` |
|
||||
| :vscode-keyboard-tab-above: | `:vscode-keyboard-tab-above:` | `vscode/keyboard-tab-above` |
|
||||
| :vscode-keyboard-tab-below: | `:vscode-keyboard-tab-below:` | `vscode/keyboard-tab-below` |
|
||||
| :vscode-law: | `:vscode-law:` | `vscode/law` |
|
||||
| :vscode-layers: | `:vscode-layers:` | `vscode/layers` |
|
||||
| :vscode-layers-active: | `:vscode-layers-active:` | `vscode/layers-active` |
|
||||
| :vscode-layers-dot: | `:vscode-layers-dot:` | `vscode/layers-dot` |
|
||||
| :vscode-layout: | `:vscode-layout:` | `vscode/layout` |
|
||||
| :vscode-layout-activitybar-left: | `:vscode-layout-activitybar-left:` | `vscode/layout-activitybar-left` |
|
||||
| :vscode-layout-activitybar-right: | `:vscode-layout-activitybar-right:` | `vscode/layout-activitybar-right` |
|
||||
| :vscode-layout-centered: | `:vscode-layout-centered:` | `vscode/layout-centered` |
|
||||
| :vscode-layout-menubar: | `:vscode-layout-menubar:` | `vscode/layout-menubar` |
|
||||
| :vscode-layout-panel: | `:vscode-layout-panel:` | `vscode/layout-panel` |
|
||||
| :vscode-layout-panel-center: | `:vscode-layout-panel-center:` | `vscode/layout-panel-center` |
|
||||
| :vscode-layout-panel-dock: | `:vscode-layout-panel-dock:` | `vscode/layout-panel-dock` |
|
||||
| :vscode-layout-panel-justify: | `:vscode-layout-panel-justify:` | `vscode/layout-panel-justify` |
|
||||
| :vscode-layout-panel-left: | `:vscode-layout-panel-left:` | `vscode/layout-panel-left` |
|
||||
| :vscode-layout-panel-off: | `:vscode-layout-panel-off:` | `vscode/layout-panel-off` |
|
||||
| :vscode-layout-panel-right: | `:vscode-layout-panel-right:` | `vscode/layout-panel-right` |
|
||||
| :vscode-layout-sidebar-left: | `:vscode-layout-sidebar-left:` | `vscode/layout-sidebar-left` |
|
||||
| :vscode-layout-sidebar-left-dock: | `:vscode-layout-sidebar-left-dock:` | `vscode/layout-sidebar-left-dock` |
|
||||
| :vscode-layout-sidebar-left-off: | `:vscode-layout-sidebar-left-off:` | `vscode/layout-sidebar-left-off` |
|
||||
| :vscode-layout-sidebar-right: | `:vscode-layout-sidebar-right:` | `vscode/layout-sidebar-right` |
|
||||
| :vscode-layout-sidebar-right-dock: | `:vscode-layout-sidebar-right-dock:` | `vscode/layout-sidebar-right-dock` |
|
||||
| :vscode-layout-sidebar-right-off: | `:vscode-layout-sidebar-right-off:` | `vscode/layout-sidebar-right-off` |
|
||||
| :vscode-layout-statusbar: | `:vscode-layout-statusbar:` | `vscode/layout-statusbar` |
|
||||
| :vscode-library: | `:vscode-library:` | `vscode/library` |
|
||||
| :vscode-lightbulb: | `:vscode-lightbulb:` | `vscode/lightbulb` |
|
||||
| :vscode-lightbulb-autofix: | `:vscode-lightbulb-autofix:` | `vscode/lightbulb-autofix` |
|
||||
| :vscode-lightbulb-empty: | `:vscode-lightbulb-empty:` | `vscode/lightbulb-empty` |
|
||||
| :vscode-lightbulb-sparkle: | `:vscode-lightbulb-sparkle:` | `vscode/lightbulb-sparkle` |
|
||||
| :vscode-link: | `:vscode-link:` | `vscode/link` |
|
||||
| :vscode-link-external: | `:vscode-link-external:` | `vscode/link-external` |
|
||||
| :vscode-list-filter: | `:vscode-list-filter:` | `vscode/list-filter` |
|
||||
| :vscode-list-flat: | `:vscode-list-flat:` | `vscode/list-flat` |
|
||||
| :vscode-list-ordered: | `:vscode-list-ordered:` | `vscode/list-ordered` |
|
||||
| :vscode-list-selection: | `:vscode-list-selection:` | `vscode/list-selection` |
|
||||
| :vscode-list-tree: | `:vscode-list-tree:` | `vscode/list-tree` |
|
||||
| :vscode-list-unordered: | `:vscode-list-unordered:` | `vscode/list-unordered` |
|
||||
| :vscode-live-share: | `:vscode-live-share:` | `vscode/live-share` |
|
||||
| :vscode-loading: | `:vscode-loading:` | `vscode/loading` |
|
||||
| :vscode-location: | `:vscode-location:` | `vscode/location` |
|
||||
| :vscode-lock: | `:vscode-lock:` | `vscode/lock` |
|
||||
| :vscode-lock-small: | `:vscode-lock-small:` | `vscode/lock-small` |
|
||||
| :vscode-magnet: | `:vscode-magnet:` | `vscode/magnet` |
|
||||
| :vscode-mail: | `:vscode-mail:` | `vscode/mail` |
|
||||
| :vscode-mail-read: | `:vscode-mail-read:` | `vscode/mail-read` |
|
||||
| :vscode-map: | `:vscode-map:` | `vscode/map` |
|
||||
| :vscode-map-filled: | `:vscode-map-filled:` | `vscode/map-filled` |
|
||||
| :vscode-map-vertical: | `:vscode-map-vertical:` | `vscode/map-vertical` |
|
||||
| :vscode-map-vertical-filled: | `:vscode-map-vertical-filled:` | `vscode/map-vertical-filled` |
|
||||
| :vscode-markdown: | `:vscode-markdown:` | `vscode/markdown` |
|
||||
| :vscode-mcp: | `:vscode-mcp:` | `vscode/mcp` |
|
||||
| :vscode-megaphone: | `:vscode-megaphone:` | `vscode/megaphone` |
|
||||
| :vscode-mention: | `:vscode-mention:` | `vscode/mention` |
|
||||
| :vscode-menu: | `:vscode-menu:` | `vscode/menu` |
|
||||
| :vscode-merge: | `:vscode-merge:` | `vscode/merge` |
|
||||
| :vscode-merge-into: | `:vscode-merge-into:` | `vscode/merge-into` |
|
||||
| :vscode-mic: | `:vscode-mic:` | `vscode/mic` |
|
||||
| :vscode-mic-filled: | `:vscode-mic-filled:` | `vscode/mic-filled` |
|
||||
| :vscode-milestone: | `:vscode-milestone:` | `vscode/milestone` |
|
||||
| :vscode-mirror: | `:vscode-mirror:` | `vscode/mirror` |
|
||||
| :vscode-mortar-board: | `:vscode-mortar-board:` | `vscode/mortar-board` |
|
||||
| :vscode-move: | `:vscode-move:` | `vscode/move` |
|
||||
| :vscode-multiple-windows: | `:vscode-multiple-windows:` | `vscode/multiple-windows` |
|
||||
| :vscode-music: | `:vscode-music:` | `vscode/music` |
|
||||
| :vscode-mute: | `:vscode-mute:` | `vscode/mute` |
|
||||
| :vscode-new-collection: | `:vscode-new-collection:` | `vscode/new-collection` |
|
||||
| :vscode-new-file: | `:vscode-new-file:` | `vscode/new-file` |
|
||||
| :vscode-new-folder: | `:vscode-new-folder:` | `vscode/new-folder` |
|
||||
| :vscode-new-session: | `:vscode-new-session:` | `vscode/new-session` |
|
||||
| :vscode-newline: | `:vscode-newline:` | `vscode/newline` |
|
||||
| :vscode-no-newline: | `:vscode-no-newline:` | `vscode/no-newline` |
|
||||
| :vscode-note: | `:vscode-note:` | `vscode/note` |
|
||||
| :vscode-notebook: | `:vscode-notebook:` | `vscode/notebook` |
|
||||
| :vscode-notebook-template: | `:vscode-notebook-template:` | `vscode/notebook-template` |
|
||||
| :vscode-octoface: | `:vscode-octoface:` | `vscode/octoface` |
|
||||
| :vscode-open-in-product: | `:vscode-open-in-product:` | `vscode/open-in-product` |
|
||||
| :vscode-open-in-window: | `:vscode-open-in-window:` | `vscode/open-in-window` |
|
||||
| :vscode-open-preview: | `:vscode-open-preview:` | `vscode/open-preview` |
|
||||
| :vscode-openai: | `:vscode-openai:` | `vscode/openai` |
|
||||
| :vscode-organization: | `:vscode-organization:` | `vscode/organization` |
|
||||
| :vscode-output: | `:vscode-output:` | `vscode/output` |
|
||||
| :vscode-package: | `:vscode-package:` | `vscode/package` |
|
||||
| :vscode-paintcan: | `:vscode-paintcan:` | `vscode/paintcan` |
|
||||
| :vscode-pass: | `:vscode-pass:` | `vscode/pass` |
|
||||
| :vscode-pass-filled: | `:vscode-pass-filled:` | `vscode/pass-filled` |
|
||||
| :vscode-percentage: | `:vscode-percentage:` | `vscode/percentage` |
|
||||
| :vscode-person: | `:vscode-person:` | `vscode/person` |
|
||||
| :vscode-person-add: | `:vscode-person-add:` | `vscode/person-add` |
|
||||
| :vscode-piano: | `:vscode-piano:` | `vscode/piano` |
|
||||
| :vscode-pie-chart: | `:vscode-pie-chart:` | `vscode/pie-chart` |
|
||||
| :vscode-pin: | `:vscode-pin:` | `vscode/pin` |
|
||||
| :vscode-pinned: | `:vscode-pinned:` | `vscode/pinned` |
|
||||
| :vscode-pinned-dirty: | `:vscode-pinned-dirty:` | `vscode/pinned-dirty` |
|
||||
| :vscode-play: | `:vscode-play:` | `vscode/play` |
|
||||
| :vscode-play-circle: | `:vscode-play-circle:` | `vscode/play-circle` |
|
||||
| :vscode-plug: | `:vscode-plug:` | `vscode/plug` |
|
||||
| :vscode-preserve-case: | `:vscode-preserve-case:` | `vscode/preserve-case` |
|
||||
| :vscode-preview: | `:vscode-preview:` | `vscode/preview` |
|
||||
| :vscode-primitive-square: | `:vscode-primitive-square:` | `vscode/primitive-square` |
|
||||
| :vscode-project: | `:vscode-project:` | `vscode/project` |
|
||||
| :vscode-pulse: | `:vscode-pulse:` | `vscode/pulse` |
|
||||
| :vscode-python: | `:vscode-python:` | `vscode/python` |
|
||||
| :vscode-question: | `:vscode-question:` | `vscode/question` |
|
||||
| :vscode-quote: | `:vscode-quote:` | `vscode/quote` |
|
||||
| :vscode-quotes: | `:vscode-quotes:` | `vscode/quotes` |
|
||||
| :vscode-radio-tower: | `:vscode-radio-tower:` | `vscode/radio-tower` |
|
||||
| :vscode-reactions: | `:vscode-reactions:` | `vscode/reactions` |
|
||||
| :vscode-record: | `:vscode-record:` | `vscode/record` |
|
||||
| :vscode-record-keys: | `:vscode-record-keys:` | `vscode/record-keys` |
|
||||
| :vscode-record-small: | `:vscode-record-small:` | `vscode/record-small` |
|
||||
| :vscode-redo: | `:vscode-redo:` | `vscode/redo` |
|
||||
| :vscode-references: | `:vscode-references:` | `vscode/references` |
|
||||
| :vscode-refresh: | `:vscode-refresh:` | `vscode/refresh` |
|
||||
| :vscode-regex: | `:vscode-regex:` | `vscode/regex` |
|
||||
| :vscode-remote: | `:vscode-remote:` | `vscode/remote` |
|
||||
| :vscode-remote-explorer: | `:vscode-remote-explorer:` | `vscode/remote-explorer` |
|
||||
| :vscode-remove: | `:vscode-remove:` | `vscode/remove` |
|
||||
| :vscode-remove-small: | `:vscode-remove-small:` | `vscode/remove-small` |
|
||||
| :vscode-rename: | `:vscode-rename:` | `vscode/rename` |
|
||||
| :vscode-replace: | `:vscode-replace:` | `vscode/replace` |
|
||||
| :vscode-replace-all: | `:vscode-replace-all:` | `vscode/replace-all` |
|
||||
| :vscode-reply: | `:vscode-reply:` | `vscode/reply` |
|
||||
| :vscode-repo: | `:vscode-repo:` | `vscode/repo` |
|
||||
| :vscode-repo-clone: | `:vscode-repo-clone:` | `vscode/repo-clone` |
|
||||
| :vscode-repo-fetch: | `:vscode-repo-fetch:` | `vscode/repo-fetch` |
|
||||
| :vscode-repo-force-push: | `:vscode-repo-force-push:` | `vscode/repo-force-push` |
|
||||
| :vscode-repo-forked: | `:vscode-repo-forked:` | `vscode/repo-forked` |
|
||||
| :vscode-repo-pinned: | `:vscode-repo-pinned:` | `vscode/repo-pinned` |
|
||||
| :vscode-repo-pull: | `:vscode-repo-pull:` | `vscode/repo-pull` |
|
||||
| :vscode-repo-push: | `:vscode-repo-push:` | `vscode/repo-push` |
|
||||
| :vscode-repo-selected: | `:vscode-repo-selected:` | `vscode/repo-selected` |
|
||||
| :vscode-report: | `:vscode-report:` | `vscode/report` |
|
||||
| :vscode-request-changes: | `:vscode-request-changes:` | `vscode/request-changes` |
|
||||
| :vscode-robot: | `:vscode-robot:` | `vscode/robot` |
|
||||
| :vscode-rocket: | `:vscode-rocket:` | `vscode/rocket` |
|
||||
| :vscode-root-folder: | `:vscode-root-folder:` | `vscode/root-folder` |
|
||||
| :vscode-root-folder-opened: | `:vscode-root-folder-opened:` | `vscode/root-folder-opened` |
|
||||
| :vscode-rss: | `:vscode-rss:` | `vscode/rss` |
|
||||
| :vscode-ruby: | `:vscode-ruby:` | `vscode/ruby` |
|
||||
| :vscode-run-above: | `:vscode-run-above:` | `vscode/run-above` |
|
||||
| :vscode-run-all: | `:vscode-run-all:` | `vscode/run-all` |
|
||||
| :vscode-run-all-coverage: | `:vscode-run-all-coverage:` | `vscode/run-all-coverage` |
|
||||
| :vscode-run-below: | `:vscode-run-below:` | `vscode/run-below` |
|
||||
| :vscode-run-coverage: | `:vscode-run-coverage:` | `vscode/run-coverage` |
|
||||
| :vscode-run-errors: | `:vscode-run-errors:` | `vscode/run-errors` |
|
||||
| :vscode-run-with-deps: | `:vscode-run-with-deps:` | `vscode/run-with-deps` |
|
||||
| :vscode-save: | `:vscode-save:` | `vscode/save` |
|
||||
| :vscode-save-all: | `:vscode-save-all:` | `vscode/save-all` |
|
||||
| :vscode-save-as: | `:vscode-save-as:` | `vscode/save-as` |
|
||||
| :vscode-screen-cut: | `:vscode-screen-cut:` | `vscode/screen-cut` |
|
||||
| :vscode-screen-full: | `:vscode-screen-full:` | `vscode/screen-full` |
|
||||
| :vscode-screen-normal: | `:vscode-screen-normal:` | `vscode/screen-normal` |
|
||||
| :vscode-search: | `:vscode-search:` | `vscode/search` |
|
||||
| :vscode-search-fuzzy: | `:vscode-search-fuzzy:` | `vscode/search-fuzzy` |
|
||||
| :vscode-search-large: | `:vscode-search-large:` | `vscode/search-large` |
|
||||
| :vscode-search-sparkle: | `:vscode-search-sparkle:` | `vscode/search-sparkle` |
|
||||
| :vscode-search-stop: | `:vscode-search-stop:` | `vscode/search-stop` |
|
||||
| :vscode-send: | `:vscode-send:` | `vscode/send` |
|
||||
| :vscode-send-to-remote-agent: | `:vscode-send-to-remote-agent:` | `vscode/send-to-remote-agent` |
|
||||
| :vscode-server: | `:vscode-server:` | `vscode/server` |
|
||||
| :vscode-server-environment: | `:vscode-server-environment:` | `vscode/server-environment` |
|
||||
| :vscode-server-process: | `:vscode-server-process:` | `vscode/server-process` |
|
||||
| :vscode-session-in-progress: | `:vscode-session-in-progress:` | `vscode/session-in-progress` |
|
||||
| :vscode-settings: | `:vscode-settings:` | `vscode/settings` |
|
||||
| :vscode-settings-gear: | `:vscode-settings-gear:` | `vscode/settings-gear` |
|
||||
| :vscode-share: | `:vscode-share:` | `vscode/share` |
|
||||
| :vscode-share-window: | `:vscode-share-window:` | `vscode/share-window` |
|
||||
| :vscode-shield: | `:vscode-shield:` | `vscode/shield` |
|
||||
| :vscode-sign-in: | `:vscode-sign-in:` | `vscode/sign-in` |
|
||||
| :vscode-sign-out: | `:vscode-sign-out:` | `vscode/sign-out` |
|
||||
| :vscode-skip: | `:vscode-skip:` | `vscode/skip` |
|
||||
| :vscode-smiley: | `:vscode-smiley:` | `vscode/smiley` |
|
||||
| :vscode-snake: | `:vscode-snake:` | `vscode/snake` |
|
||||
| :vscode-sort-precedence: | `:vscode-sort-precedence:` | `vscode/sort-precedence` |
|
||||
| :vscode-source-control: | `:vscode-source-control:` | `vscode/source-control` |
|
||||
| :vscode-sparkle: | `:vscode-sparkle:` | `vscode/sparkle` |
|
||||
| :vscode-sparkle-filled: | `:vscode-sparkle-filled:` | `vscode/sparkle-filled` |
|
||||
| :vscode-split-horizontal: | `:vscode-split-horizontal:` | `vscode/split-horizontal` |
|
||||
| :vscode-split-vertical: | `:vscode-split-vertical:` | `vscode/split-vertical` |
|
||||
| :vscode-squirrel: | `:vscode-squirrel:` | `vscode/squirrel` |
|
||||
| :vscode-star-empty: | `:vscode-star-empty:` | `vscode/star-empty` |
|
||||
| :vscode-star-full: | `:vscode-star-full:` | `vscode/star-full` |
|
||||
| :vscode-star-half: | `:vscode-star-half:` | `vscode/star-half` |
|
||||
| :vscode-stop-circle: | `:vscode-stop-circle:` | `vscode/stop-circle` |
|
||||
| :vscode-strikethrough: | `:vscode-strikethrough:` | `vscode/strikethrough` |
|
||||
| :vscode-surround-with: | `:vscode-surround-with:` | `vscode/surround-with` |
|
||||
| :vscode-symbol-array: | `:vscode-symbol-array:` | `vscode/symbol-array` |
|
||||
| :vscode-symbol-boolean: | `:vscode-symbol-boolean:` | `vscode/symbol-boolean` |
|
||||
| :vscode-symbol-class: | `:vscode-symbol-class:` | `vscode/symbol-class` |
|
||||
| :vscode-symbol-color: | `:vscode-symbol-color:` | `vscode/symbol-color` |
|
||||
| :vscode-symbol-constant: | `:vscode-symbol-constant:` | `vscode/symbol-constant` |
|
||||
| :vscode-symbol-enum: | `:vscode-symbol-enum:` | `vscode/symbol-enum` |
|
||||
| :vscode-symbol-enum-member: | `:vscode-symbol-enum-member:` | `vscode/symbol-enum-member` |
|
||||
| :vscode-symbol-event: | `:vscode-symbol-event:` | `vscode/symbol-event` |
|
||||
| :vscode-symbol-field: | `:vscode-symbol-field:` | `vscode/symbol-field` |
|
||||
| :vscode-symbol-file: | `:vscode-symbol-file:` | `vscode/symbol-file` |
|
||||
| :vscode-symbol-interface: | `:vscode-symbol-interface:` | `vscode/symbol-interface` |
|
||||
| :vscode-symbol-key: | `:vscode-symbol-key:` | `vscode/symbol-key` |
|
||||
| :vscode-symbol-keyword: | `:vscode-symbol-keyword:` | `vscode/symbol-keyword` |
|
||||
| :vscode-symbol-method: | `:vscode-symbol-method:` | `vscode/symbol-method` |
|
||||
| :vscode-symbol-method-arrow: | `:vscode-symbol-method-arrow:` | `vscode/symbol-method-arrow` |
|
||||
| :vscode-symbol-misc: | `:vscode-symbol-misc:` | `vscode/symbol-misc` |
|
||||
| :vscode-symbol-namespace: | `:vscode-symbol-namespace:` | `vscode/symbol-namespace` |
|
||||
| :vscode-symbol-numeric: | `:vscode-symbol-numeric:` | `vscode/symbol-numeric` |
|
||||
| :vscode-symbol-operator: | `:vscode-symbol-operator:` | `vscode/symbol-operator` |
|
||||
| :vscode-symbol-parameter: | `:vscode-symbol-parameter:` | `vscode/symbol-parameter` |
|
||||
| :vscode-symbol-property: | `:vscode-symbol-property:` | `vscode/symbol-property` |
|
||||
| :vscode-symbol-ruler: | `:vscode-symbol-ruler:` | `vscode/symbol-ruler` |
|
||||
| :vscode-symbol-snippet: | `:vscode-symbol-snippet:` | `vscode/symbol-snippet` |
|
||||
| :vscode-symbol-string: | `:vscode-symbol-string:` | `vscode/symbol-string` |
|
||||
| :vscode-symbol-structure: | `:vscode-symbol-structure:` | `vscode/symbol-structure` |
|
||||
| :vscode-symbol-variable: | `:vscode-symbol-variable:` | `vscode/symbol-variable` |
|
||||
| :vscode-sync: | `:vscode-sync:` | `vscode/sync` |
|
||||
| :vscode-sync-ignored: | `:vscode-sync-ignored:` | `vscode/sync-ignored` |
|
||||
| :vscode-table: | `:vscode-table:` | `vscode/table` |
|
||||
| :vscode-tag: | `:vscode-tag:` | `vscode/tag` |
|
||||
| :vscode-target: | `:vscode-target:` | `vscode/target` |
|
||||
| :vscode-tasklist: | `:vscode-tasklist:` | `vscode/tasklist` |
|
||||
| :vscode-telescope: | `:vscode-telescope:` | `vscode/telescope` |
|
||||
| :vscode-terminal: | `:vscode-terminal:` | `vscode/terminal` |
|
||||
| :vscode-terminal-bash: | `:vscode-terminal-bash:` | `vscode/terminal-bash` |
|
||||
| :vscode-terminal-cmd: | `:vscode-terminal-cmd:` | `vscode/terminal-cmd` |
|
||||
| :vscode-terminal-debian: | `:vscode-terminal-debian:` | `vscode/terminal-debian` |
|
||||
| :vscode-terminal-git-bash: | `:vscode-terminal-git-bash:` | `vscode/terminal-git-bash` |
|
||||
| :vscode-terminal-linux: | `:vscode-terminal-linux:` | `vscode/terminal-linux` |
|
||||
| :vscode-terminal-powershell: | `:vscode-terminal-powershell:` | `vscode/terminal-powershell` |
|
||||
| :vscode-terminal-secure: | `:vscode-terminal-secure:` | `vscode/terminal-secure` |
|
||||
| :vscode-terminal-tmux: | `:vscode-terminal-tmux:` | `vscode/terminal-tmux` |
|
||||
| :vscode-terminal-ubuntu: | `:vscode-terminal-ubuntu:` | `vscode/terminal-ubuntu` |
|
||||
| :vscode-text-size: | `:vscode-text-size:` | `vscode/text-size` |
|
||||
| :vscode-thinking: | `:vscode-thinking:` | `vscode/thinking` |
|
||||
| :vscode-three-bars: | `:vscode-three-bars:` | `vscode/three-bars` |
|
||||
| :vscode-thumbsdown: | `:vscode-thumbsdown:` | `vscode/thumbsdown` |
|
||||
| :vscode-thumbsdown-filled: | `:vscode-thumbsdown-filled:` | `vscode/thumbsdown-filled` |
|
||||
| :vscode-thumbsup: | `:vscode-thumbsup:` | `vscode/thumbsup` |
|
||||
| :vscode-thumbsup-filled: | `:vscode-thumbsup-filled:` | `vscode/thumbsup-filled` |
|
||||
| :vscode-tools: | `:vscode-tools:` | `vscode/tools` |
|
||||
| :vscode-trash: | `:vscode-trash:` | `vscode/trash` |
|
||||
| :vscode-triangle-down: | `:vscode-triangle-down:` | `vscode/triangle-down` |
|
||||
| :vscode-triangle-left: | `:vscode-triangle-left:` | `vscode/triangle-left` |
|
||||
| :vscode-triangle-right: | `:vscode-triangle-right:` | `vscode/triangle-right` |
|
||||
| :vscode-triangle-up: | `:vscode-triangle-up:` | `vscode/triangle-up` |
|
||||
| :vscode-twitter: | `:vscode-twitter:` | `vscode/twitter` |
|
||||
| :vscode-type-hierarchy: | `:vscode-type-hierarchy:` | `vscode/type-hierarchy` |
|
||||
| :vscode-type-hierarchy-sub: | `:vscode-type-hierarchy-sub:` | `vscode/type-hierarchy-sub` |
|
||||
| :vscode-type-hierarchy-super: | `:vscode-type-hierarchy-super:` | `vscode/type-hierarchy-super` |
|
||||
| :vscode-unarchive: | `:vscode-unarchive:` | `vscode/unarchive` |
|
||||
| :vscode-unfold: | `:vscode-unfold:` | `vscode/unfold` |
|
||||
| :vscode-ungroup-by-ref-type: | `:vscode-ungroup-by-ref-type:` | `vscode/ungroup-by-ref-type` |
|
||||
| :vscode-unlock: | `:vscode-unlock:` | `vscode/unlock` |
|
||||
| :vscode-unmute: | `:vscode-unmute:` | `vscode/unmute` |
|
||||
| :vscode-unverified: | `:vscode-unverified:` | `vscode/unverified` |
|
||||
| :vscode-variable-group: | `:vscode-variable-group:` | `vscode/variable-group` |
|
||||
| :vscode-verified: | `:vscode-verified:` | `vscode/verified` |
|
||||
| :vscode-verified-filled: | `:vscode-verified-filled:` | `vscode/verified-filled` |
|
||||
| :vscode-versions: | `:vscode-versions:` | `vscode/versions` |
|
||||
| :vscode-vm: | `:vscode-vm:` | `vscode/vm` |
|
||||
| :vscode-vm-active: | `:vscode-vm-active:` | `vscode/vm-active` |
|
||||
| :vscode-vm-connect: | `:vscode-vm-connect:` | `vscode/vm-connect` |
|
||||
| :vscode-vm-outline: | `:vscode-vm-outline:` | `vscode/vm-outline` |
|
||||
| :vscode-vm-pending: | `:vscode-vm-pending:` | `vscode/vm-pending` |
|
||||
| :vscode-vm-running: | `:vscode-vm-running:` | `vscode/vm-running` |
|
||||
| :vscode-vm-small: | `:vscode-vm-small:` | `vscode/vm-small` |
|
||||
| :vscode-vr: | `:vscode-vr:` | `vscode/vr` |
|
||||
| :vscode-vscode: | `:vscode-vscode:` | `vscode/vscode` |
|
||||
| :vscode-vscode-insiders: | `:vscode-vscode-insiders:` | `vscode/vscode-insiders` |
|
||||
| :vscode-wand: | `:vscode-wand:` | `vscode/wand` |
|
||||
| :vscode-warning: | `:vscode-warning:` | `vscode/warning` |
|
||||
| :vscode-watch: | `:vscode-watch:` | `vscode/watch` |
|
||||
| :vscode-whitespace: | `:vscode-whitespace:` | `vscode/whitespace` |
|
||||
| :vscode-whole-word: | `:vscode-whole-word:` | `vscode/whole-word` |
|
||||
| :vscode-window: | `:vscode-window:` | `vscode/window` |
|
||||
| :vscode-window-active: | `:vscode-window-active:` | `vscode/window-active` |
|
||||
| :vscode-word-wrap: | `:vscode-word-wrap:` | `vscode/word-wrap` |
|
||||
| :vscode-workspace-trusted: | `:vscode-workspace-trusted:` | `vscode/workspace-trusted` |
|
||||
| :vscode-workspace-unknown: | `:vscode-workspace-unknown:` | `vscode/workspace-unknown` |
|
||||
| :vscode-workspace-untrusted: | `:vscode-workspace-untrusted:` | `vscode/workspace-untrusted` |
|
||||
| :vscode-worktree: | `:vscode-worktree:` | `vscode/worktree` |
|
||||
| :vscode-worktree-small: | `:vscode-worktree-small:` | `vscode/worktree-small` |
|
||||
| :vscode-zoom-in: | `:vscode-zoom-in:` | `vscode/zoom-in` |
|
||||
| :vscode-zoom-out: | `:vscode-zoom-out:` | `vscode/zoom-out` |
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
icon: simple/devbox
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# :simple-devbox: Для разработчиков
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
- [:material-application-brackets-outline: Среда разработки](local-dev.md)
|
||||
|
||||
---
|
||||
Настройка ПО для работы с кодом проекта
|
||||
|
||||
- [:material-robot-outline: Telegram-бот](tgbot.md)
|
||||
|
||||
---
|
||||
Специфика разработки и отладки Telegram-бота проекта
|
||||
|
||||
- [:material-book-cog-outline: Сборка документации](docs.md)
|
||||
|
||||
---
|
||||
Как скорректировать, проверить и скомплировать эту документацию
|
||||
|
||||
- [:material-upload-network: Развёртывание и доставка обновлений](deploy.md)
|
||||
|
||||
---
|
||||
О том, как опубликовать изменения на сервере
|
||||
</div>
|
||||
@@ -0,0 +1,221 @@
|
||||
---
|
||||
# icon: material/architecture
|
||||
tags: ["iptvc", "разработка", "архитектура"]
|
||||
---
|
||||
|
||||
# Архитектура iptvc
|
||||
|
||||
Внутреннее устройство программы для разработчиков.
|
||||
|
||||
## Стек технологий
|
||||
|
||||
- **Go 1.22+** — язык программирования;
|
||||
- `net/http` — HTTP-сервер (Go 1.22 routing patterns);
|
||||
- `html/template` — шаблоны HTML;
|
||||
- `//go:embed` — встраивание шаблонов в бинарник;
|
||||
- `github.com/spf13/cobra` — CLI-фреймворк;
|
||||
- `gopkg.in/yaml.v3` — парсинг `config.yml`;
|
||||
- `github.com/joho/godotenv` — загрузка `.env`;
|
||||
- `github.com/redis/go-redis/v9` — клиент KeyDB/Redis.
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
iptvc/
|
||||
├── main.go # точка входа
|
||||
├── config.yml # конфигурация
|
||||
├── .env # переменные окружения (опционально)
|
||||
├── cmd/ # CLI-команды (Cobra)
|
||||
│ ├── root.go # корневая команда, глобальные флаги
|
||||
│ ├── check.go # команда check
|
||||
│ ├── serve.go # команда serve
|
||||
│ ├── flags.go # общие флаги check/serve
|
||||
│ └── version.go # команда version
|
||||
├── app/
|
||||
│ ├── app.go # глобальные переменные: Args, Config, Cache
|
||||
│ ├── config/
|
||||
│ │ └── config.go # Config, Init(), validate(), IntRange, UserAgents
|
||||
│ ├── checker/
|
||||
│ │ └── checker.go # CheckPlaylists(), CheckChannels(), OnPlaylistChecked
|
||||
│ ├── playlist/
|
||||
│ │ └── playlist.go # Playlist, Channel, Parse(), Download()
|
||||
│ ├── inifile/
|
||||
│ │ └── inifile.go # чтение playlists.ini
|
||||
│ ├── tagfile/
|
||||
│ │ └── tagfile.go # чтение channels.json, назначение тегов
|
||||
│ ├── cache/
|
||||
│ │ └── cache.go # подключение к KeyDB/Redis
|
||||
│ ├── logger/
|
||||
│ │ └── logger.go # настройка логирования
|
||||
│ ├── utils/
|
||||
│ │ └── utils.go # Fetch(), ExpandPath(), ArrayUnique(), Md5str()
|
||||
│ └── web/
|
||||
│ ├── server.go # Server, Start(), StartBackgroundChecker()
|
||||
│ ├── handlers.go # HTTP-обработчики
|
||||
│ ├── templates.go # TemplateManager, //go:embed
|
||||
│ └── views/ # HTML-шаблоны
|
||||
│ ├── layout.html
|
||||
│ ├── list.html
|
||||
│ └── details.html
|
||||
└── go.mod
|
||||
```
|
||||
|
||||
## Пакеты
|
||||
|
||||
### `app`
|
||||
|
||||
Глобальный контейнер: `Args` (CLI-флаги), `Config` (конфигурация), `Cache` (Redis-клиент).
|
||||
`Init()` загружает конфигурацию, инициализирует логгер и подключение к кешу.
|
||||
|
||||
### `app.config`
|
||||
|
||||
Структуры: `Config` → `AppConfig`, `ServerConfig`, `CheckConfig`, `CacheConfig`.
|
||||
|
||||
Кастомные YAML-типы:
|
||||
|
||||
- **`IntRange`** — скаляр или `[min, max]`. Метод `Value()` возвращает константу или случайное значение.
|
||||
- **`UserAgents`** — строка или массив строк. Метод `Pick()` возвращает случайный элемент.
|
||||
|
||||
`Init(configPath)` — загружает `config.yml`, применяет env, валидирует.
|
||||
|
||||
`validate()` — проверяет все значения, исправляет некорректные с логированием.
|
||||
|
||||
### `app.checker`
|
||||
|
||||
Содержит логику проверки:
|
||||
|
||||
- **`PrepareListsToCheck(files, urls, codes)`** — формирует список плейлистов из файлов, URL и кодов ini-файла.
|
||||
- **`CheckPlaylists(lists)`** — параллельная проверка плейлистов (семфор `per-routine`), загрузка, парсинг, вызов `CheckChannels` для каждого.
|
||||
- **`CheckChannels(pls)`** — параллельная проверка каналов (семфор `per-routine`), HTTP-запрос с `Range` header.
|
||||
- **`OnPlaylistChecked`** — глобальный callback, вызывается после проверки каждого плейлиста. Используется веб-сервером для обновления in-memory кеша.
|
||||
- **`cachePlaylist(pls)`** — сохранение результата в Redis (если включён).
|
||||
|
||||
Параметры проверки берутся из `app.Config.Check.Playlists` и `app.Config.Check.Channels`.
|
||||
|
||||
### `app.playlist`
|
||||
|
||||
- **`Playlist`** — плейлист: код, URL, контент, каналы, статус.
|
||||
- **`Channel`** — канал: ID, название, URL, статус, теги.
|
||||
- **`Download(userAgent, timeout)`** — загрузка по URL.
|
||||
- **`ReadFromFs()`** — чтение из файла.
|
||||
- **`Parse()`** — парсинг m3u/m3u8 контента.
|
||||
|
||||
### `app.web`
|
||||
|
||||
Веб-сервер на `net/http` (Go 1.22 routing).
|
||||
|
||||
- **`Server`** — структура: конфиг, кеш, шаблоны, in-memory кеш (`memCache` с `sync.RWMutex`).
|
||||
- **`Start()`** — запуск HTTP-сервера.
|
||||
- **`StartBackgroundChecker(opts)`** — фоновая проверка в отдельной горутине.
|
||||
- **`CheckOptions`** — параметры: Every, Repeat, Random, Files, Urls, Codes.
|
||||
|
||||
Маршруты (Go 1.22 patterns):
|
||||
|
||||
```
|
||||
GET /api/playlists/{code} — JSON плейлиста
|
||||
GET /api/version — версия
|
||||
GET /api/health — здоровье сервиса
|
||||
GET /api/stats — статистика
|
||||
GET /{$} — главная (catch-all root)
|
||||
GET /{path...} — все остальные маршруты (catch-all)
|
||||
```
|
||||
|
||||
Catch-all `/{path...}` используется для избежания конфликтов паттернов в Go 1.22 mux.
|
||||
|
||||
In-memory кеш (`memCache`) обновляется через `OnPlaylistChecked` callback.
|
||||
Это позволяет отображать результаты проверки в реальном времени без ожидания завершения цикла и без Redis.
|
||||
|
||||
ini-файл кешируется на 30 секунд, кеш сбрасывается при каждом обновлении `memCache`.
|
||||
|
||||
## Жизненный цикл `serve --check`
|
||||
|
||||
```
|
||||
main → app.Init() → web.NewServer() → go StartBackgroundChecker() → server.Start()
|
||||
|
||||
StartBackgroundChecker:
|
||||
loop:
|
||||
runCheckerOnce()
|
||||
→ checker.PrepareListsToCheck()
|
||||
→ checker.CheckPlaylists()
|
||||
→ for each playlist (parallel, per-routine):
|
||||
→ Download() / ReadFromFs()
|
||||
→ Parse()
|
||||
→ CheckChannels()
|
||||
→ for each channel (parallel, per-routine):
|
||||
→ HTTP GET with Range header
|
||||
→ check status + content type
|
||||
→ OnPlaylistChecked(pls) → memCache update
|
||||
→ one-cooldown sleep
|
||||
→ all-cooldown sleep
|
||||
sleep(every)
|
||||
if repeat > 0 && iteration >= repeat: stop
|
||||
```
|
||||
|
||||
## CLI-флаги
|
||||
|
||||
### Общие (`cmd/flags.go`)
|
||||
|
||||
Используются командами `check` и `serve --check`:
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| --- | --- | --- |
|
||||
| `-i, --ini` | `Args.IniPath` | Путь к playlists.ini |
|
||||
| `-t, --tags` | `Args.TagsPath` | Путь к channels.json |
|
||||
| `-r, --random` | `Args.RandomCount` | Случайные N плейлистов |
|
||||
| `--repeat` | `Args.RepeatCount` | Количество циклов (0 = бесконечно) |
|
||||
| `--every` | `Args.RepeatEverySec` | Секунд между циклами |
|
||||
|
||||
### Только `check` (`addCheckOnlyFlags`)
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| --- | --- | --- |
|
||||
| `-j, --json` | `Args.NeedJson` | Вывод в JSON |
|
||||
| `-q, --quiet` | `Args.NeedQuiet` | Подавить логи |
|
||||
| `-f, --file` | `Args.Files` | Локальные m3u файлы |
|
||||
| `-u, --url` | `Args.Urls` | URL плейлистов |
|
||||
| `-c, --code` | `Args.Codes` | Коды из ini-файла |
|
||||
|
||||
### Только `serve`
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| --- | --- | --- |
|
||||
| `-p, --port` | `Args.ServerPort` | Порт веб-сервера |
|
||||
| `--host` | `Args.ServerHost` | Хост привязки |
|
||||
| `--check` | `Args.NeedCheck` | Включить фоновую проверку |
|
||||
|
||||
### Глобальные (`cmd/root.go`)
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| --- | --- | --- |
|
||||
| `--config` | `Args.ConfigPath` | Путь к config.yml |
|
||||
| `-v, --verbose` | `Args.Verbose` | Подробный лог |
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Подробное описание параметров — в разделе [config.yml](../config.md).
|
||||
|
||||
Приоритет: Defaults < `config.yml` < Env < CLI-флаги.
|
||||
|
||||
CLI-флаги переопределяют конфигурацию только если переданы явно (`cmd.Flags().Changed()`).
|
||||
Для этого в Cobra используются zero-value defaults (0, "", false), чтобы отличить «не передан» от «передан со значением по умолчанию».
|
||||
|
||||
## Шаблоны
|
||||
|
||||
HTML-шаблоны встроены через `//go:embed`:
|
||||
|
||||
- `layout.html` — общий каркас (header, footer);
|
||||
- `list.html` — список плейлистов с пагинацией;
|
||||
- `details.html` — детали плейлиста и список каналов.
|
||||
|
||||
SVG-логотипы каналов передаются через `encodeURIComponent` в data-URI для корректной работы с кавычками в HTML.
|
||||
|
||||
При отсутствии `playlists.ini` рендерится пустое состояние с alert-блоком.
|
||||
|
||||
## Кеширование
|
||||
|
||||
Два уровня кеша:
|
||||
|
||||
1. **Redis/KeyDB** (опционально) — постоянный кеш результатов проверки. TTL из `cache.ttl`.
|
||||
2. **In-memory** (`memCache`) — только при `serve --check`. Обновляется в реальном времени через callback. Не требует Redis.
|
||||
|
||||
In-memory кеш приоритетнее Redis при отображении в веб-интерфейсе.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
icon: material/application-brackets-outline
|
||||
---
|
||||
|
||||
# :material-application-brackets-outline: Среда разработки
|
||||
|
||||
Полная информация о развёртывании локальной среды расположена здесь:
|
||||
|
||||
https://git.axenov.dev/IPTV/iptv-docker/src/branch/master/README.md
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
icon: material/robot-outline
|
||||
---
|
||||
|
||||
# :material-robot-outline: Telegram-бот
|
||||
|
||||
!!! info "Обрати внимание"
|
||||
Локальная среда разработки должна быть [настроена и запущена](local-dev.md).
|
||||
|
||||
## Подготовка бота на стороне Telegram
|
||||
|
||||
1. Написать [@botfather](https://t.me/botfather), создать бота
|
||||
2. Полученный токен установить значением переменной `TG_BOT_TOKEN` в файле `.env` репозитория `web`
|
||||
3. Командой `/mybots` в [@botfather](https://t.me/botfather) выбрать свежесозданного бота, далее `Edit Bot` > `Edit Commands` и отправить текст:
|
||||
```
|
||||
list - Список плейлистов
|
||||
info - Подробности о плейлисте по его коду
|
||||
help - Помощь по командам бота
|
||||
links - Ссылки на все страницы проекта
|
||||
stats - Статистика по плейлистам и каналам
|
||||
```
|
||||
|
||||
## Проброс внешних запросов на локальную машину
|
||||
|
||||
1. Установить [telebit](https://telebit.cloud) и пройти примитивную регистрацию.
|
||||
В результате будет выдан уникальный адрес в формате `https://foo-bar-99.telebit.io`.
|
||||
На email, указанный при регистрации, будет оформлен бесплатный SSL-серификат Let's Encrypt для этого домена.
|
||||
Если адрес не используется месяц+, то сертификат протухнет, но он автоматически восстановится, если адрес начнёт использоваться вновь.
|
||||
|
||||
2. В терминале выполнить:
|
||||
```
|
||||
telebit http 8080
|
||||
```
|
||||
где `8080` — порт локальной машины, на который проброшен порт 80 из контейнера `iptv-nginx`.
|
||||
Для выключения выполнить:
|
||||
```
|
||||
telebit http
|
||||
```
|
||||
|
||||
3. Проверить работу адреса, перейдя по нему браузером.
|
||||
Должен открыться твой локальный проект.
|
||||
|
||||
4. Полученный адрес установить значением переменной `APP_URL` в файле `.env` репозитория `web`
|
||||
|
||||
5. Установить веб-хук, отправив запрос браузером или любым HTTP-клиентом на адрес:
|
||||
```
|
||||
https://api.telegram.org/bot$BOT_TOKEN/setWebhook?url=$TELEBIT_URL/bot/webhook&secret_token=$SECRET_TOKEN
|
||||
```
|
||||
где:
|
||||
* `$BOT_TOKEN` - авторизационный токен, который @botfather выдал твоему боту;
|
||||
* `$TELEBIT_URL` - адрес, который telebit выдал тебе;
|
||||
* `$SECRET_TOKEN` - секретный токен, опционален, см. ниже.
|
||||
|
||||
6. Проверить веб-хук, отправив запрос браузером или любым HTTP-клиентом на адрес:
|
||||
```
|
||||
https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo
|
||||
```
|
||||
где:
|
||||
* `$BOT_TOKEN` - авторизационный токен, который @botfather выдал твоему боту.
|
||||
|
||||
7. После разработки нужно установить "боевой" адрес веб-хука аналогично п4.
|
||||
|
||||
## Что за секретный токен?
|
||||
|
||||
Telegram авторизует твоего бота по токену, который выдал ему сам.
|
||||
|
||||
Ты тоже можешь (не) авторизовать Telegram по токену, который ты выдашь ему.
|
||||
|
||||
Для этого нужно в значением переменной `TG_BOT_SECRET` в файле `.env` репозитория `web` установить любую строку.
|
||||
Если ты это сделаешь, тогда ту же строку ты должен передать в параметре `secret_token` метода `setWebhook`.
|
||||
|
||||
В этом случае, все HTTP-запросы, которые приходят от Telegram, будут содержать заголовок `X-Telegram-Bot-Api-Secret-Token` со этой строкой в качестве значения.
|
||||
Эта строка сверяется с той, что указана в `.env` проекта.
|
||||
Если такого заголовка нет или его значение некорректно, входящий запрос отклоняется.
|
||||
|
||||
Если переменная `TG_BOT_SECRET` не задана, то заголовок проверяться не будет.
|
||||
|
||||
См. подробности в документации: [setWebhook](https://core.telegram.org/bots/api#setwebhook)
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: channels.json
|
||||
icon: material/code-json
|
||||
tags: ["iptvc", "теги", "каналы"]
|
||||
---
|
||||
|
||||
# :material-code-json: Формат файла `channels.json`
|
||||
|
||||
Категории каналов указываются в файле `channels.json` в следующем формате:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"tvg-id": "регулярное выражение для значения атрибута tvg-id",
|
||||
"tvg-name": "регулярное выражение для значения атрибута tvg-name",
|
||||
"title": "регулярное выражение для названия канала",
|
||||
"tags": [
|
||||
"список",
|
||||
"тегов",
|
||||
"(см. ниже)"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Приоритет параметров:
|
||||
|
||||
* `tvg-id`
|
||||
* `tvg-name`
|
||||
* `title`
|
||||
|
||||
Если указаны все или несколько, то применится только тот один, который по приоритету выше.
|
||||
|
||||
Параметр `tags` обязателен, список может быть (не)пустым.
|
||||
Категории в списке указываются в двойных кавычках.
|
||||
После каждой категории, кроме последней, ставится запятая.
|
||||
|
||||
Регулярные выражения должны быть PCRE-совместимыми.
|
||||
|
||||
Каналы сопоставляются в нижнем регистре.
|
||||
|
||||
<a id="warnings"></a>
|
||||
## Рекомендации и предостережения
|
||||
|
||||
1. Если хочешь написать новое правило, будь осторожен с регулярками.
|
||||
Старайся не охватывать несколько каналов сразу.
|
||||
Если канал попадёт в несколько регулярок, то его **теги могут оказаться неожиданными** и найти проблему может быть сложно.
|
||||
2. Указывай внутри `{}` только `tags` и один из параметров `tvg-id`, `tvg-name` или `title`.
|
||||
Множество параметров на точность не влияет, зато будет проще уместить всё правило в одну строку и grep-ать файл.
|
||||
3. Не забывай, что название на кириллице не всегда означает, что это российский канал или вещание на русском языке.
|
||||
4. Разные каналы могут быть названы одинаково или похоже.
|
||||
Например, `Первый канал`, `Первый Тульский`, `Первый городской`.
|
||||
5. Один канал может быть назван по-разному.
|
||||
Например, `Ю` или `Ю!`, `Россия 1 +5` или `Россия-1`.
|
||||
6. Важно учитывать холдинги.
|
||||
Например, российские Матч, ТНТ и НТВ имеют множество разных каналов, и тупо искать `^нтв$` — тупо.
|
||||
7. У всех каналов есть `title`.
|
||||
Не все каналы имеют `tvg-id`.
|
||||
Некоторые каналы имеют `tvg-name`.
|
||||
Все три параметра могут оказаться на кириллице.
|
||||
|
||||
<a id="доступные-теги">
|
||||
## Доступные теги
|
||||
|
||||
| Ключевое слово | Описание |
|
||||
| -------------- | ----------------------------------------------------------- |
|
||||
| `untagged` | Неизвестно (ставится по умолчанию, если нет иных) |
|
||||
| `unstable` | Нестабильные каналы |
|
||||
| `hd` | Каналы в высоком качестве |
|
||||
| `4k` | Каналы в супервысоком качестве |
|
||||
| `8k` | Каналы в гигавысоком качестве (а вдруг?) |
|
||||
| `adult` | Контент для взрослых 18+ |
|
||||
| `army` | Каналы военные, об оружии, технике, армии, боевых действиях |
|
||||
| `central` | Центральное ТВ (гос. каналы, федеральные) |
|
||||
| `child` | Детские и подростковые каналы |
|
||||
| `culture` | Каналы о культуре, театре |
|
||||
| `crime` | Каналы с детективами и о преступлениях (true-crime) |
|
||||
| `cyber` | Киберспортивные |
|
||||
| `docs` | Каналы с документальными фильмами |
|
||||
| `fashion` | Мода и стиль |
|
||||
| `film` | Каналы с фильмами |
|
||||
| `finance` | Бизнес, финансы, капитал |
|
||||
| `food` | Кулинарные каналы |
|
||||
| `fun` | Развлекательные каналы и шоу |
|
||||
| `garden` | Сад, огород, фермерство, домашнее хозяйство |
|
||||
| `health` | Каналы о здоровье |
|
||||
| `history` | Исторические каналы |
|
||||
| `house` | О строительстве, ремонте, интерьере и жилье |
|
||||
| `humor` | Юмористические каналы, комедии |
|
||||
| `hunt-fish` | Охота и рыбалка |
|
||||
| `local` | Местные региональные каналы |
|
||||
| `music` | Музыкальные |
|
||||
| `mystic` | Каналы о мистике, потустороннем, НЛО и прочей пиздаболии |
|
||||
| `nature` | Каналы о природе, животных |
|
||||
| `news` | Новостные каналы |
|
||||
| `politic` | Каналы политические, партийные, правительстенные |
|
||||
| `radio` | Радиоканалы (радиостанции, подкасты, аудиоспектакли...) |
|
||||
| `religion` | Религиозные каналы |
|
||||
| `retro` | Ностальгия и ретро, музыка, старые передачи |
|
||||
| `sci` | Научные и познавательные |
|
||||
| `series` | Каналы с сериалами |
|
||||
| `shopping` | Телемагазины |
|
||||
| `sport` | Спортивные |
|
||||
| `tech` | Каналы о технологиях |
|
||||
| `transport` | Каналы о транспорте (авто, мото, ЖД...) |
|
||||
| `travel` | Каналы о путешествиях |
|
||||
| `webcam` | Уличные веб-камеры |
|
||||
|
||||
Также в категориях можно указывать страну вещания.
|
||||
Это должен быть буквенный код АЛЬФА-2 из общероссийского классификатора стран мира (ОКСМ):
|
||||
|
||||
* [normativ.kontur.ru](https://normativ.kontur.ru/document?moduleId=1&documentId=22668#h1296)
|
||||
* [classifikators.ru](https://classifikators.ru/oksm)
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
icon: material/file-code-outline
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# :material-file-code-outline: Форматы файлов
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
- [:material-code-brackets: Формат файла `playlists.ini`](playlists.md)
|
||||
|
||||
---
|
||||
Список плейлистов, которые отображаются на сайте и периодически проверяются
|
||||
|
||||
- [:material-code-json: Формат файла `channels.json`](channels.md)
|
||||
|
||||
---
|
||||
Список правил для применения тегов к разным каналам
|
||||
|
||||
- [:material-playlist-play: Формат файлов `*.m3u` (`*.m3u8`)](m3u.md)
|
||||
|
||||
---
|
||||
Плейлист — это вообще что?
|
||||
</div>
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
title: "*.m3u (*.m3u8)"
|
||||
icon: material/playlist-play
|
||||
tags: ["плейлисты", "каналы"]
|
||||
---
|
||||
|
||||
# :material-playlist-play: Формат файлов `*.m3u` (`*.m3u8`)
|
||||
|
||||
Формат применяется для составления мультимедиа плейлистов, как оффлайн, так и онлайн.
|
||||
|
||||
Разница между m3u и m3u8 уже давно отсутствует, но исторически так сложилось, то m3u8 должен был быть только в формате UTF-8.
|
||||
|
||||
Директивы начинаются с новой строки и символа `#`.
|
||||
У каждой директивы могут (не) быть атрибуты, которые следуют в одну строку.
|
||||
|
||||
После директив с новой строки указывается ссылка на канал (или путь к файлу).
|
||||
|
||||
В свою чередь, по этой ссылке может быть:
|
||||
|
||||
* либо текстовое представление контента в формате m3u/m3u8/XMLTV/MPD с описанием непосредственно участки трансляции;
|
||||
* либо непосредственно сама потоковая трансляция mp4 или т. п.
|
||||
|
||||
Рассмотрим на выдуманном примере плейлиста IPTV:
|
||||
|
||||
```m3u
|
||||
#EXTM3U url-tvg="https://iptvx.one/EPG" catchup="append" catchup-days="3" catchup-source="?offset=-${offset}&utcstart=${timestamp}"
|
||||
|
||||
#EXTINF:-1 tvg-id="ntv" tvg-logo="http://epg.it999.ru/img2/2001.png",НТВ HD
|
||||
#EXTGRP:🇷🇺 Эфирные
|
||||
http://example.com/play-ntv.m3u
|
||||
|
||||
#EXTINF:-1 tvg-logo="http://tvoetv.space/tvoetv.png" tvg-id="tvoetv",Твоё ТВ HD v8 с VPN
|
||||
http://example.com/play-tvoetv.m3u
|
||||
|
||||
#EXTINF:0 tvg-name="BBC" audio-track="eng" tvg-logo="http://mylogos.domain/BBC.png", BBC World
|
||||
http://example.com/play-bbc.m3u
|
||||
|
||||
#EXTINF:-1 tvg-id="5TV.am" tvg-country="AM" tvg-language="Armenian" tvg-logo="https://i.imgur.com/yigw9dr.png" user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" group-title="General",5-րդ ալիք (480p)
|
||||
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148
|
||||
#EXTVLCOPT:http-caching=1200
|
||||
http://example.com/play-am.m3u8
|
||||
```
|
||||
|
||||
<a id="EXTM3U"></a>
|
||||
### Директива `#EXTM3U`
|
||||
|
||||
Заголовок файла (обязателен).
|
||||
|
||||
<a id="url-tvg"></a>
|
||||
#### Атрибут `url-tvg` (он же `x-tvg-url`)
|
||||
|
||||
Ссылка программу передач в формате `*.xml` или `*.xml.gz`.
|
||||
|
||||
<a id="catchup"></a>
|
||||
#### Атрибуты `catchup*`
|
||||
|
||||
Читай здесь: [Архив телепрограмм (SS IPTV)](https://ss-iptv.com/ru/operators/catchup)
|
||||
|
||||
<a id="EXTGRP"></a>
|
||||
### Директива `#EXTGRP`
|
||||
|
||||
Название группы, к которой относится контент (звуковая дорожка или канал).
|
||||
|
||||
Указывается в формате `#EXTGRP:XXX`, где: `XXX` — название группы.
|
||||
|
||||
<a id="EXTINF"></a>
|
||||
### Директива `#EXTINF`
|
||||
|
||||
Описывает контент (звуковую дорожку или канал).
|
||||
|
||||
Указывается в формате `#EXTINF:XXX YYY,ZZZ`, где:
|
||||
* `XXX` — длительность в секундах (обязательно, но может быть `-1` или `0`);
|
||||
* `YYY` — атрибуты (см. ниже);
|
||||
* `ZZZ` — название контента;
|
||||
|
||||
<a id="tvg-shift"></a>
|
||||
#### Атрибут `tvg-shift`
|
||||
|
||||
Cмещение телепрограммы в часах относительно указанного в программе.
|
||||
|
||||
<a id="tvg-id"></a>
|
||||
<a id="tvg-name"></a>
|
||||
#### Атрибуты `tvg-id` и `tvg-name`
|
||||
|
||||
Идентификатор телепрограммы канала.
|
||||
По нему телепрограмма привязывается к трансляции с учётом смещения времени.
|
||||
|
||||
<a id="tvg-logo"></a>
|
||||
#### Атрибут `tvg-logo`
|
||||
|
||||
Ссылка на логотип канала.
|
||||
|
||||
<a id="tvg-country"></a>
|
||||
#### Атрибут `tvg-country`
|
||||
|
||||
Код Alpha-2 страны вещания согласно ISO 3166-1 или ОКСМ.
|
||||
|
||||
<a id="tvg-language"></a>
|
||||
#### Атрибут `tvg-language`
|
||||
|
||||
Название языка телепередачи согласно ISO 639-2.
|
||||
|
||||
<a id="group-title"></a>
|
||||
#### Атрибут `group-title`
|
||||
|
||||
Название группы.
|
||||
По функционалу идентичен директиве `#EXTGRP`.
|
||||
|
||||
<a id="user-agent"></a>
|
||||
#### Атрибут `user-agent`
|
||||
|
||||
Значение заголовка `User-Agent` для обращения к контенту по http.
|
||||
|
||||
<a id="audio-track"></a>
|
||||
#### Атрибут `audio-track`
|
||||
|
||||
Языковой код (ISO 639-2) аудио дорожки канала, например: "eng,rus".
|
||||
|
||||
Допускается указание нескольких аудио дорожек через запятую: "rus,ukr,eng".
|
||||
|
||||
Дорожкой по умолчанию устанавливается первая указанная в списке.
|
||||
|
||||
<a id="aspect-ratio"></a>
|
||||
#### Атрибут `aspect-ratio`
|
||||
|
||||
Определяет пропорции экрана (может быть недоступно для некоторых моделей телевизоров).
|
||||
|
||||
Допустимые значения: 16:9, 3:2, 4:3, 1,85:1, 2,39:1 (наиболее распространенное значение для фильмов)
|
||||
|
||||
<a id="EXTVLCOPT"></a>
|
||||
### Директива `#EXTVLCOPT`
|
||||
|
||||
Специфична для VLC Player.
|
||||
Директив может быть множество для одной дорожки (канала).
|
||||
|
||||
Указывается в формате `#EXTVLCOPT:XXX` или `#EXTVLCOPT--XXX=YYY`, где:
|
||||
* `XXX` — параметр командной строки VLC Player ([полный список](https://wiki.videolan.org/VLC_command-line_help/));
|
||||
* `YYY` — значения параметра.
|
||||
|
||||
## Дополнительные материалы
|
||||
|
||||
* [Инструкция по формату M3U (SS IPTV)](https://ss-iptv.com/ru/users/documents/m3u)
|
||||
* [Архив телепрограмм (SS IPTV)](https://ss-iptv.com/ru/operators/catchup)
|
||||
* [VLC command-line help](https://wiki.videolan.org/VLC_command-line_help/)
|
||||
* [ISO 639-2 Codes for the Representation of Names of Languages](https://www.loc.gov/standards/iso639-2/php/code_list.php)
|
||||
* [ISO 3166-1 Wikipedia](https://en.wikipedia.org/wiki/ISO_3166-1)
|
||||
* ОКСМ:
|
||||
* [normativ.kontur.ru](https://normativ.kontur.ru/document?moduleId=1&documentId=22668#h1296)
|
||||
* [classifikators.ru](https://classifikators.ru/oksm)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: playlists.ini
|
||||
icon: material/code-brackets
|
||||
tags: ["плейлисты"]
|
||||
---
|
||||
|
||||
# :material-code-brackets: Формат файла `playlists.ini`
|
||||
|
||||
Рассмотрим на примере:
|
||||
|
||||
```ini
|
||||
[code]
|
||||
name = Рабочий автообновляемый IPTV плейлист M3U
|
||||
desc = "В этом IPTV плейлисте есть каналы в высоком качестве"
|
||||
pls = 'https://example.com/pls.m3u'
|
||||
src = 'https://example.com/super-duper-playlist'
|
||||
# комментарий 1
|
||||
; ещё один комментарий
|
||||
```
|
||||
|
||||
Перенос строк невозможен.
|
||||
Комментарии игнорируются.
|
||||
|
||||
Для значений можно (не) использовать 'одинарные' или "двойные" кавычки.
|
||||
Ради единообразия рекомендуется использовать 'одинарные'.
|
||||
|
||||
## `code`
|
||||
|
||||
Код плейлиста в рамках этого конфига (**обязательно**).
|
||||
|
||||
Должен быть коротким и уникальным.
|
||||
|
||||
Подставляется в короткую ссылку, по которой произойдёт переадресация на прямой адрес `pls`.
|
||||
|
||||
!!! note
|
||||
Для удобства ввода с пульта, код рекомендуется задавать числом или короткой строкой без пробелов и др. спецсимволов.
|
||||
Чем короче, тем лучше.
|
||||
|
||||
## `name`
|
||||
|
||||
Название плейлиста (необязательно).
|
||||
|
||||
По умолчанию: `Playlist #<code>`.
|
||||
|
||||
## `desc`
|
||||
|
||||
Краткое описание из источника или от себя (необязательно).
|
||||
|
||||
По умолчанию: пусто.
|
||||
|
||||
## `pls`
|
||||
|
||||
Прямая ссылка на m3u/m3u8 плейлист (**обязательно**).
|
||||
|
||||
## `src`
|
||||
|
||||
Ссылка на источник (страницу сайта), откуда был взят плейлист (необязательно).
|
||||
|
||||
По умолчанию: пусто.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
icon: material/download
|
||||
tags: ["iptvc"]
|
||||
---
|
||||
|
||||
# Установка и запуск
|
||||
|
||||
## Запуск готовой программы
|
||||
|
||||
Достаточно скачать и распаковать архив с подходящим исполняемым файлом [со страницы последнего релиза][rel_page] в любую удобную директорию:
|
||||
|
||||
| ОС | Скачать для `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] |
|
||||
|
||||
[rel_page]: https://git.axenov.dev/IPTV/iptvc/releases/latest
|
||||
[linux_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_amd64.zip
|
||||
[linux_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_arm64.zip
|
||||
[darwin_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_amd64.zip
|
||||
[darwin_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_arm64.zip
|
||||
[windows_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_amd64.zip
|
||||
[windows_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_arm64.zip
|
||||
|
||||
## Запуск релизного образа
|
||||
|
||||
Релизные docker-образы строятся для платформы `linux` и архитектуры `amd64`.
|
||||
|
||||
Найти их можно здесь: <https://git.axenov.dev/IPTV/-/packages/container/iptvc>
|
||||
|
||||
Тег `latest` всегда соответствует последней версии, он подразумевается по умолчанию:
|
||||
|
||||
=== "Запуск последней версии"
|
||||
|
||||
```shell
|
||||
docker run \
|
||||
--pull always \
|
||||
--name iptvc \
|
||||
git.axenov.dev/iptv/iptvc \ #(1)!
|
||||
КОМАНДА [АРГУМЕНТЫ]
|
||||
```
|
||||
|
||||
1. Подразумевается `:latest`, можно указать явно
|
||||
|
||||
=== "Запуск другой версии"
|
||||
|
||||
```shell
|
||||
docker run \
|
||||
--pull always \
|
||||
--name iptvc \
|
||||
git.axenov.dev/iptv/iptvc:v1.0.6 \ #(1)!
|
||||
КОМАНДА [АРГУМЕНТЫ]
|
||||
```
|
||||
|
||||
1. Список версий доступен на [релизной странице][rel_page]
|
||||
|
||||
## Использование образа в Docker compose
|
||||
|
||||
```yaml title="compose.yml"
|
||||
services:
|
||||
#...
|
||||
iptvc:
|
||||
container_name: iptvc
|
||||
image: git.axenov.dev/iptv/iptvc:latest
|
||||
command: [serve] #(1)!
|
||||
#...
|
||||
```
|
||||
|
||||
1. Доступные команды и аргументы см. в [**Справочнике команд**](commands/index.md)
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Введение
|
||||
icon: octicons/sparkles-fill-16
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# IPTV Checker (iptvc)
|
||||
|
||||
Это простая программа для проверки IPTV плейлистов, входящая в состав проекта m3u.su.
|
||||
|
||||
Поддерживает проверку как локальных файлов `*.m3u`/`*.m3u8`, так и удалённых плейлистов по прямым ссылкам, с возможностью кеширования результатов и его вывода в различных форматах.
|
||||
|
||||
> Программа не предназначена для хранения, воспроизведения или распространения пиратского контента.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
- :material-flag-checkered: **Быстрый старт**
|
||||
|
||||
---
|
||||
|
||||
Коротко о главном, если не терпится
|
||||
|
||||
[Подробности :material-arrow-right:][start]{ .md-button .md-button--primary }
|
||||
|
||||
- :material-application-brackets-outline: **Запуск сайта**
|
||||
|
||||
---
|
||||
|
||||
Создайте свой агрегатор плейлистов
|
||||
|
||||
[Подробности :material-arrow-right:][site]{ .md-button .md-button--primary }
|
||||
|
||||
- :octicons-terminal-24: **Работа в терминале**
|
||||
|
||||
---
|
||||
|
||||
Как обрабатывать плейлисты без GUI
|
||||
|
||||
[Подробности :material-arrow-right:][cli]{ .md-button .md-button--primary }
|
||||
|
||||
- :material-file-cog: **Конфигурация**
|
||||
|
||||
---
|
||||
|
||||
Настройте `iptvc` для своих целей
|
||||
|
||||
[Подробности :material-arrow-right:][cfg]{ .md-button .md-button--primary }
|
||||
</div>
|
||||
|
||||
[start]: quickstart.md "Перейти к разделу"
|
||||
[site]: site/index.md "Перейти к разделу"
|
||||
[cli]: commands/index.md "Перейти к разделу"
|
||||
[cfg]: config/config.md "Перейти к разделу"
|
||||
|
||||
<!--
|
||||
## :material-cog-sync-outline: Как работает `iptvc`
|
||||
|
||||
Принцип её работы очень простой:
|
||||
|
||||
1. Получить плейлист по ссылке.
|
||||
2. Полученный плейлист распарсить:
|
||||
обрабатывается полученный текст в формате [m3u](../formats/m3u.md), из него вычленется информация о каналах и их группировке.
|
||||
3. Каждый найденный канал проверить:
|
||||
получить информацию по ссылке и принять решение — работает ли канал (технически) или нет.
|
||||
4. Если необходимо, каждому каналу [присвоить теги](../formats/channels.md#доступные-теги) согласно [правилам](../formats/channels.md).
|
||||
5. Если необходимо, закешировать результаты проверок.
|
||||
|
||||
Во время работы программа пишет лог проверки плейлиста и каналов в достаточно компактном человекочитаемом виде, а в конце пишет результаты проверок.
|
||||
|
||||
При желании, можно включить более подробный вывод, чтобы тщательно следить за ходом проверки в реальном времени, а также вывод результатов в машиночитаемом виде (в формате json).
|
||||
|
||||
Подробности см. в разделе [Команда `check`](../iptvc/commands/check.md).
|
||||
|
||||
-->
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
icon: material/flag-checkered
|
||||
tags: ["iptvc"]
|
||||
---
|
||||
|
||||
# :material-flag-checkered: Быстрый старт
|
||||
|
||||
Для простоты представим, что программа скачана и распакована в любую директорию и вы находитесь в ней.
|
||||
|
||||
Используйте тот способ запуска, который выбрали на шаге [установки](install.md).
|
||||
|
||||
Ниже представлены лишь частые примеры запуска программы с разными аргументами под разные случаи.
|
||||
|
||||
## Проверить плейлист по прямой ссылке
|
||||
|
||||
```
|
||||
./iptvc check -u https://example.com/pls.m3u
|
||||
./iptvc check --url https://example.com/pls.m3u
|
||||
```
|
||||
|
||||
## Проверить файл плейлиста с диска
|
||||
|
||||
```
|
||||
./iptvc check -f /home/user/pls.m3u
|
||||
./iptvc check --file /home/user/pls.m3u
|
||||
```
|
||||
|
||||
## Проверить плейлист по короткому коду из [`playlists.ini`](formats/playlists.md)
|
||||
|
||||
```
|
||||
./iptvc check -c X
|
||||
./iptvc check --code X
|
||||
```
|
||||
|
||||
Файл `playlists.ini` должен лежать рядом с `iptvc`.
|
||||
|
||||
Если файл лежит в другой директории, то можно явно указать путь к нему:
|
||||
|
||||
```
|
||||
./iptvc check --ini /home/user/playlists.ini --code X
|
||||
```
|
||||
|
||||
Если ini-файл не будет найден, программа предупредит об этом.
|
||||
|
||||
## Присвоить каналам тематические теги
|
||||
|
||||
Для этого рядом с `iptvc` должен лежать файл [channels.json](formats/channels.md).
|
||||
|
||||
Если файл лежит в другой директории, то можно указать её явно:
|
||||
|
||||
```
|
||||
./iptvc check --tags /home/user/channels.json
|
||||
```
|
||||
|
||||
Если json-файл не будет найден, то программа предупредит о том, что теги не будут присвоены, и продолжит работу.
|
||||
|
||||
## Проверить несколько плейлистов одновременно
|
||||
|
||||
Для этого можно комбинировать все аргументы, перечисленные выше, с учётом особенностей их работы:
|
||||
|
||||
```shell
|
||||
./iptvc check \
|
||||
--ini /home/user/p.ini \ #(1)!
|
||||
--tags /home/user/c.json \ #(2)!
|
||||
--code Y \ #(3)!
|
||||
--file /home/user/tv.m3u \ #(4)!
|
||||
--url https://example.com/pls1.m3u \ #(5)!
|
||||
-u https://example.com/pls2.m3u #(6)!
|
||||
```
|
||||
|
||||
1. Из этого файла будет взят список плейлистов
|
||||
2. Из этого файла будут взяты правила для присвоения тегов каналам
|
||||
3. Из ini-списка будет проверен только плейлист с кодом `Y`
|
||||
4. Это отдельный файл плейлиста на диске, который будет проверен в дополнение к основному списку
|
||||
5. Плейлист на каком-то удалённом сервере, который будет загружен и проверен вместе с прошлыми двумя
|
||||
6. Ещё один по ссылке, просто через короткий вариант аргумента `--url`
|
||||
|
||||
Символ `\` нужен только для наглядного разделения аргументов на несколько строк.
|
||||
Всё это можно писать в одну строку.
|
||||
|
||||
Переданные плейлисты будут обработаны в следующем порядке:
|
||||
|
||||
1. локальные файлы (`-f|--file`);
|
||||
2. по ссылкам (`-u|--url`);
|
||||
3. по кодам из ini-файла (`-i|--ini`, `-c|--code`).
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
icon: material/television-play
|
||||
tags: ["плееры", "плейлисты"]
|
||||
---
|
||||
|
||||
# :material-television-play: Как подключить плейлист
|
||||
|
||||
1. Найти какой-нибудь [плеер](./players.md)
|
||||
2. Узнать как в него добавить плейлист по ссылке
|
||||
3. Найти желаемый плелист из [списка](./list.md)
|
||||
4. Найти на странице ["Ссылку для ТВ"](details.md#shortlink) и ввести (скопировать) её в поле ввода адреса в плеере
|
||||
|
||||
Для некоторых [плееров](./players.md) уже есть информация как добавить плейлист.
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
icon: material/table-eye
|
||||
tags: ["сайт", "статусы", "каналы"]
|
||||
---
|
||||
|
||||
# :material-table-eye: Страница плейлиста
|
||||
|
||||
Страница содержит подробности об одном конкретном плейлисте.
|
||||
|
||||
В её заголовке указано [название плейлиста](../formats/playlists.md#name).
|
||||
|
||||
Ниже страница разделена на две части: слева две вкладки с информацией и список каналов справа.
|
||||
|
||||
Рассмотрим всё это подробнее.
|
||||
|
||||
## Вкладка "Основная информация"
|
||||
|
||||

|
||||
|
||||
На этой вкладке выводится таблица со следующими строками:
|
||||
|
||||
* **Код** — короткий уникальный [код плейлиста](../formats/playlists.md#code);
|
||||
* **Описание** — [описание плейлиста](../formats/playlists.md#desc) (при наличии);
|
||||
* **Ccылка для ТВ** — короткая ссылка, которую можно использовать для [подключения плейлиста](../common/connect.md), подробнее о ней см. ниже;
|
||||
* **Источник** — [ссылка на ресурс](../formats/playlists.md#src), где была найдена ссылка на плейлист (при наличии);
|
||||
* **Наполнение**:
|
||||
* группы — количество групп, на которые поделены каналы;
|
||||
* каналы — количества каналов общее, онлайн и оффлайн;
|
||||
(всё по нулям, если плейлист <span class="badge offline">offline</span>)
|
||||
* **Возможности** — наличие программы передач и перемотки каналов;
|
||||
* **M3U** — [прямая ссылка](../formats/playlists.md#pls) на плейлист;
|
||||
* **Проверка плейлиста** — дата и время последней [проверки](../common/checks.md) плейлиста с помощью [iptvc](../iptvc/index.md);
|
||||
* **Ошибка проверки** — текст ошибки, которая возникла при проверке
|
||||
(только если плейлист <span class="badge offline">offline</span>)
|
||||
|
||||
Если при проверке плейлиста возникла ошибка, то она будет отображена красным цветом сразу под заголовком:
|
||||
|
||||
??? quote "Скриншот страницы с ошибкой"
|
||||

|
||||
|
||||
!!! info
|
||||
Если в тексте ошибки фигурирует слово `Timeout` и плейлист <span class="badge offline">offline</span> — это ерунда.
|
||||
Скорее всего, при следующей проверке статус позеленеет.
|
||||
Просто в момент проверки сервер не получил файл плейлиста вовремя, а т. к. долго ждать он не может, поэтому плюнул и пошёл проверять другие.
|
||||
|
||||
!!! info "Обрати внимание"
|
||||
Независимо от статуса плейлиста на сайте, его можно добавить в свой плеер по "Ссылке для ТВ" и проверить самостоятельно.
|
||||
Проверка плейлиста не влияет на его работоспособность.
|
||||
|
||||
## Вкладка "Исходный текст"
|
||||
|
||||

|
||||
|
||||
Здесь выводится плейлист как он есть.
|
||||
Над этим текстом — две кнопки:
|
||||
|
||||
* зелёная с кодом плейлиста для скачивания файла;
|
||||
* нажатие на **QR-код** покажет, внезапно, QR-код, в который закодирована "Ссылка для ТВ".
|
||||
|
||||
## Список каналов
|
||||
|
||||
В заголовке пишется их общее количество.
|
||||
|
||||

|
||||
|
||||
В списке всегда отображается не более 100 каналов.
|
||||
|
||||
Воспользуйтесь поиском, чтобы найти интересующий.
|
||||
|
||||
### Поиск каналов
|
||||
|
||||
Количество плейлистов в заголовке над списком учитывает найденные с помощью фильтров каналы.
|
||||
|
||||
Под заголовком есть **выпадающий список групп**.
|
||||
Он отображается только если плейлист поделён на группы.
|
||||
Справа — **кнопка сброса** для отображения всех каналов.
|
||||
|
||||
Под списком групп расположилась **строка поиска**.
|
||||
Она есть вообще всегда.
|
||||
Туда можно начать вводить название канала, и по мере ввода список будет сужаться.
|
||||
|
||||
Справа от строки поиска есть **кнопки фильтрации каналов по их статусу**.
|
||||
Справа — **кнопка сброса** для отображения всех каналов.
|
||||
|
||||
Под строкой поиска есть [**облако тегов**](../formats/channels.md#доступные-теги).
|
||||
|
||||
!!! question inline end "Про теги"
|
||||
Откуда они там появляются, можешь прочесть [здесь](../common/index.md) и [здесь](../iptvc/index.md).
|
||||
|
||||
На любой из них можно нажать, и тогда в списке останутся каналы только с выбранными тегами.
|
||||
Выбранные теги подсвечиваются серым.
|
||||
**Сбросить** выбор можно повторным нажатием на каждый, либо кнопкой сброса у строки поиска.
|
||||
|
||||
??? quote "Пример фильтрации"
|
||||

|
||||
|
||||
<a id="shortlink"></a>
|
||||
## Ссылка для ТВ
|
||||
|
||||
Она может быть задана в нескольких форматах.
|
||||
Поясню базовые принципы формирования адреса:
|
||||
|
||||
1. необязателен префикс протокола `http://` или `https://` перед доменом
|
||||
2. обязателен домен `m3u.su`
|
||||
3. обязателен `/код` плейлиста после домена
|
||||
4. необязателен суффикс расширения после кода `.m3u` или `.m3u8`
|
||||
|
||||
На примере ниже я наглядно покажу все возможные ссылки на один и тот же плейлист с кодом `ru`:
|
||||
|
||||
```
|
||||
https://m3u.su/ru.m3u8
|
||||
https://m3u.su/ru.m3u
|
||||
https://m3u.su/ru
|
||||
http://m3u.su/ru.m3u8
|
||||
http://m3u.su/ru.m3u
|
||||
http://m3u.su/ru
|
||||
m3u.su/ru.m3u8
|
||||
m3u.su/ru.m3u
|
||||
m3u.su/ru
|
||||
```
|
||||
|
||||
!!! info ""
|
||||
Запоминать их не надо.
|
||||
Главное помнить как они формируются.
|
||||
|
||||
По идее, можешь использовать любую сылку из подобных, т. к. технически они отработают одинаково.
|
||||
|
||||
А вот твой [плеер](players.md) может не принять какую-то из них.
|
||||
Так что, если не подойдёт один формат, используй другой — добавь префикс или суффикс.
|
||||
|
||||
Префикс плееру требуется чаще всего, потому что он при добавлении плейлиста проверяет — а ссылку ли мне вообще предоставил пользователь?
|
||||
|
||||
По наличию суффикса плеер может определить — а прямая ли это ссылка на файл плейлиста?
|
||||
Технически — нет, непрямая, потому что файла плейлиста у меня на сервере нет физически и сервер должен сделать редирект уже на сам плейлист.
|
||||
Но благодаря такой обманке плеер его наверняка подгрузит.
|
||||
|
||||
Или нет.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
icon: fontawesome/solid/list-check
|
||||
tags: ["сайт", "плейлисты"]
|
||||
---
|
||||
|
||||
# :fontawesome-solid-list-check: Список плейлистов
|
||||
|
||||
Это главная страница сайта.
|
||||
|
||||

|
||||
|
||||
Наверху отображаются:
|
||||
|
||||
* дата последнего изменения файла [playlists.ini](../formats/playlists.md)
|
||||
* общее количество плейлистов и с разделением по статусам.
|
||||
|
||||
Ниже — спиcок плейлистов.
|
||||
|
||||
## Из чего состоит список
|
||||
|
||||
* **Код** — короткий уникальный [код плейлиста](../formats/playlists.md#code)
|
||||
* **Информация о плейлисте**
|
||||
* [статус плейлиста](../common/checks.md#playlists)
|
||||
* может быть [значок 18+](../common/checks.md#adult)
|
||||
* [название плейлиста](../formats/playlists.md#name) — ссылка на [страницу плейлиста](../common/details.md)
|
||||
под ним:
|
||||
* [иконки возможностей плейлиста](../common/checks.md#extra) (только при статусе <span class="badge online">online</span>)
|
||||
* [описание плейлиста](../formats/playlists.md#desc) (при наличии)
|
||||
* [список тегов](../formats/channels.md#доступные-теги), собранный со всех каналов после их проверки (только при статусе <span class="badge online">online</span>)
|
||||
* ещё одна ссылка на [страницу плейлиста](../common/details.md)
|
||||
* **Каналов** — фактическое количество каналов в плейлисте (только при статусе <span class="badge online">online</span>) или 0 (при других статусах)
|
||||
* **Ссылка для ТВ** — [короткая ссылка](details.md#shortlink), которую можно использовать для [подключения плейлиста](../common/connect.md).
|
||||
|
||||
В зависимости от ширины экрана, для экономии места может быть скрыто описание с иконками возможностей и короткая ссылка.
|
||||
|
||||

|
||||
@@ -0,0 +1,392 @@
|
||||
---
|
||||
title: Запуск своего сайта
|
||||
icon: material/rocket-launch
|
||||
tags: ["iptvc", "serve", "сайт"]
|
||||
---
|
||||
|
||||
# :material-rocket-launch: Запуск своего сайта
|
||||
|
||||
В этой статье мы шаг за шагом запустим собственный сайт-агрегатор IPTV-плейлистов — от простейшего варианта до полной конфигурации с кешем и тонкой настройкой проверки.
|
||||
|
||||
Программа `iptvc` уже должна быть [установлена](../install.md). Все команды ниже выполняются в терминале из директории, где лежит бинарник.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 1. Запускаем пустой сайт
|
||||
|
||||
Минимальный запуск — одна команда:
|
||||
|
||||
```bash
|
||||
./iptvc serve
|
||||
```
|
||||
|
||||
Сайт откроется на `http://localhost:8080`. Это пустая страница: нет ни одного плейлиста, потому что программе пока неоткуда их взять.
|
||||
|
||||
Чтобы изменить порт или хост, не трогая файл конфигурации:
|
||||
|
||||
```bash
|
||||
./iptvc serve -p 3000 --host 0.0.0.0
|
||||
```
|
||||
|
||||
Подробнее об этих флагах — в [документации команды `serve`](../commands/serve.md).
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2. Добавляем плейлисты
|
||||
|
||||
Список плейлистов описывается в файле [`playlists.ini`](../formats/playlists.md). Создадим его рядом с `iptvc`:
|
||||
|
||||
```ini title="playlists.ini"
|
||||
[ru]
|
||||
name = Российские каналы
|
||||
desc = Основные федеральные каналы
|
||||
pls = 'https://example.com/ru.m3u'
|
||||
src = 'https://example.com/ru-playlist'
|
||||
|
||||
[movies]
|
||||
name = Фильмы
|
||||
pls = 'https://example.com/movies.m3u'
|
||||
```
|
||||
|
||||
Каждая секция `[code]` — это плейлист. Код используется в коротких ссылках вида `http://localhost:8080/ru`. Параметр `pls` обязателен, остальные — по желанию.
|
||||
|
||||
Теперь запустим:
|
||||
|
||||
```bash
|
||||
./iptvc serve
|
||||
```
|
||||
|
||||
Сайт покажет оба плейлиста, но их статус — `unknown` (неизвестно). Это нормально: программа знает о них, но ещё не проверяла. Чтобы статусы появились, нужно включить фоновую проверку.
|
||||
|
||||
!!! tip "Путь к ini-файлу"
|
||||
Если файл лежит не рядом с программой, укажите путь через флаг [`-i`](../commands/serve.md#ini) или в [`config.yml`](../config/config.md) → `app.playlists`.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3. Включаем фоновую проверку
|
||||
|
||||
Без проверки сайт просто показывает список. Чтобы плейлисты и каналы проверялись автоматически, добавим флаг `--check`:
|
||||
|
||||
```bash
|
||||
./iptvc serve --check
|
||||
```
|
||||
|
||||
Теперь программа в фоне загружает каждый плейлист, парсит каналы и проверяет их доступность. Результаты сразу попадают в оперативную память и отображаются на сайте.
|
||||
|
||||
Можно настроить интервал между циклами проверки:
|
||||
|
||||
```bash
|
||||
# проверять каждые 120 секунд, бесконечно
|
||||
./iptvc serve --check --every 120
|
||||
|
||||
# проверить один раз и остановить
|
||||
./iptvc serve --check --repeat 1
|
||||
```
|
||||
|
||||
Если не хочется каждый раз писать `--check`, можно включить проверку через [`config.yml`](../config/config.md):
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
start-on-serve: true
|
||||
```
|
||||
|
||||
Тогда обычный `./iptvc serve` автоматически запустит фоновую проверку.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4. Настраиваем внешний вид сайта
|
||||
|
||||
Сайт можно настроить под себя: заголовок, иконку, навигацию в шапке и ссылки в подвале. Всё это — в секции [`site`](../config/config.md#секция-site) файла `config.yml`.
|
||||
|
||||
```yaml title="config.yml"
|
||||
site:
|
||||
base-url: http://localhost:8080
|
||||
repo-url: https://git.axenov.dev/IPTV
|
||||
page-size: 20 # пагинация по 20 плейлистов на страницу (0 — без пагинации)
|
||||
favicon: /favicon.ico # путь к иконке
|
||||
header:
|
||||
title: Мой IPTV # заголовок в шапке и вкладке браузера
|
||||
navigation:
|
||||
- title: Документация
|
||||
url: /docs
|
||||
icon: document-text-outline
|
||||
- title: Telegram
|
||||
icon: paper-plane-outline
|
||||
children:
|
||||
- title: Канал
|
||||
url: https://t.me/my_channel
|
||||
icon: megaphone-outline
|
||||
- title: Чат
|
||||
url: https://t.me/my_chat
|
||||
icon: chatbubbles-outline
|
||||
footer-links:
|
||||
- title: Исходники
|
||||
url: https://git.axenov.dev/IPTV
|
||||
icon: code-slash-outline
|
||||
- title: Мой сайт
|
||||
url: https://example.com
|
||||
icon: person-outline
|
||||
```
|
||||
|
||||
--8<-- "ionicons-name.md"
|
||||
|
||||
!!! note "base-url"
|
||||
Параметр `base-url` используется для формирования внутренних ссылок. Если публикуете сайт на домене, укажите его здесь, например `https://my-iptv.ru`.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 5. Добавляем теги каналам
|
||||
|
||||
Теги помогают посетителям находить каналы по темам: спорт, фильмы, музыка и так далее. Правила описываются в файле [`channels.json`](../formats/channels.md).
|
||||
|
||||
```json title="channels.json"
|
||||
[
|
||||
{
|
||||
"tvg-id": "^ru-",
|
||||
"tags": ["russian"]
|
||||
},
|
||||
{
|
||||
"title": "спорт",
|
||||
"tags": ["sport"]
|
||||
},
|
||||
{
|
||||
"title": "кино|фильм",
|
||||
"tags": ["film"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Путь к файлу указывается в [`config.yml`](../config/config.md) → `app.tags` или через флаг [`-t`](../commands/serve.md#tags):
|
||||
|
||||
```bash
|
||||
./iptvc serve --check -t /path/to/channels.json
|
||||
```
|
||||
|
||||
Полный список доступных тегов — в [справочнике по channels.json](../formats/channels.md#доступные-теги).
|
||||
|
||||
---
|
||||
|
||||
## Шаг 6. Подключаем кеш (KeyDB/Redis)
|
||||
|
||||
По умолчанию результаты проверки хранятся только в оперативной памяти. Если программу перезапустить — все результаты пропадут, и плейлисты снова станут `unknown` до следующей проверки.
|
||||
|
||||
Кеш решает эту проблему: результаты сохраняются в KeyDB (или Redis) и переживают перезапуск. Включается одной строкой в [`config.yml`](../config/config.md#секция-cache):
|
||||
|
||||
```yaml title="config.yml"
|
||||
cache:
|
||||
enabled: true
|
||||
host: localhost
|
||||
port: 6379
|
||||
ttl: 1800 # секунды (30 минут)
|
||||
```
|
||||
|
||||
Или через переменные окружения:
|
||||
|
||||
```bash
|
||||
CACHE_ENABLED=true CACHE_TTL=3600 ./iptvc serve --check
|
||||
```
|
||||
|
||||
Или через флаги:
|
||||
|
||||
```bash
|
||||
./iptvc serve --check --cache-enabled --cache-host 192.168.1.10 --cache-ttl 3600
|
||||
```
|
||||
|
||||
!!! tip "KeyDB или Redis"
|
||||
KeyDB — это форк Redis, полностью совместимый по протоколу. Подойдёт любой из них. Если кеш включён, но сервер недоступен — сайт продолжит работать, просто без кеширования.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 7. Тонкая настройка проверки
|
||||
|
||||
Когда плейлистов много, полезно управлять параллелизмом, таймаутами и задержками. Все параметры — в секции [`check`](../config/config.md#секция-check) файла `config.yml`.
|
||||
|
||||
### Параллелизм
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
playlists:
|
||||
max-routines: 10 # сколько плейлистов проверять одновременно
|
||||
per-routine: 5 # сколько плейлистов в одной процедуре
|
||||
channels:
|
||||
max-routines: 100 # сколько каналов проверять одновременно
|
||||
per-routine: 20 # сколько каналов в одной процедуре
|
||||
```
|
||||
|
||||
Чем больше значения — тем быстрее проверка, но выше нагрузка на процессор и сеть. Начните со значений по умолчанию и увеличивайте при необходимости.
|
||||
|
||||
### Таймауты
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
playlists:
|
||||
timeout: 10000 # мс на загрузку плейлиста
|
||||
channels:
|
||||
timeout: 10000 # мс на проверку одного канала
|
||||
byte-range: 512 # сколько байт скачать от сервера канала
|
||||
```
|
||||
|
||||
Если плейлисты или каналы медленные, увеличьте `timeout`. Если сервер блокирует большие запросы — уменьшите `byte-range`.
|
||||
|
||||
### Задержки (cooldown)
|
||||
|
||||
Чтобы не перегружать серверы-источники, между проверками можно делать паузы. Параметры поддерживают как фиксированное значение, так и диапазон `[min, max]` — тогда пауза будет случайной при каждом проходе:
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
playlists:
|
||||
all-cooldown: 5000 # 5 секунд после всех плейлистов
|
||||
one-cooldown: [1000, 3000] # 1–3 секунды после каждого плейлиста
|
||||
channels:
|
||||
cooldown: [100, 500] # 100–500 мс после каждого канала
|
||||
```
|
||||
|
||||
### User-Agent
|
||||
|
||||
Некоторые серверы блокируют запросы без правильного User-Agent. Можно указать один или несколько — тогда при каждом запросе будет выбран случайный:
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
playlists:
|
||||
user-agent:
|
||||
- Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||
- Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||
channels:
|
||||
user-agent: Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||
```
|
||||
|
||||
Все эти параметры можно также задавать через [переменные окружения](../config/env.md) или [CLI-флаги](../commands/serve.md) — они имеют наивысший приоритет.
|
||||
|
||||
---
|
||||
|
||||
## Полный пример
|
||||
|
||||
Соберём всё вместе в одном `config.yml`:
|
||||
|
||||
```yaml title="config.yml"
|
||||
app:
|
||||
timezone: GMT+3
|
||||
debug: false
|
||||
log_level: info
|
||||
playlists: ./playlists.ini
|
||||
tags: ./channels.json
|
||||
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
port: 8080
|
||||
|
||||
site:
|
||||
base-url: https://my-iptv.ru
|
||||
repo-url: https://git.axenov.dev/IPTV
|
||||
page-size: 20
|
||||
favicon: /favicon.ico
|
||||
header:
|
||||
title: Мой IPTV
|
||||
navigation:
|
||||
- title: Статус
|
||||
url: https://status.my-iptv.ru
|
||||
icon: pulse-outline
|
||||
- title: Документация
|
||||
url: /docs
|
||||
icon: document-text-outline
|
||||
- title: Telegram
|
||||
icon: paper-plane-outline
|
||||
children:
|
||||
- title: Канал
|
||||
url: https://t.me/my_channel
|
||||
icon: megaphone-outline
|
||||
- title: Чат
|
||||
url: https://t.me/my_chat
|
||||
icon: chatbubbles-outline
|
||||
footer-links:
|
||||
- title: Исходники
|
||||
url: https://git.axenov.dev/IPTV
|
||||
icon: code-slash-outline
|
||||
- title: Контакты
|
||||
url: https://example.com
|
||||
icon: person-outline
|
||||
|
||||
check:
|
||||
start-on-serve: true
|
||||
playlists:
|
||||
user-agent:
|
||||
- Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||
- Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||
timeout: 10000
|
||||
all-cooldown: 5000
|
||||
one-cooldown: [1000, 3000]
|
||||
max-routines: 10
|
||||
per-routine: 5
|
||||
channels:
|
||||
user-agent: Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||
timeout: 10000
|
||||
byte-range: 512
|
||||
cooldown: [100, 500]
|
||||
max-routines: 100
|
||||
per-routine: 20
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
host: localhost
|
||||
port: 6379
|
||||
ttl: 3600
|
||||
```
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
./iptvc serve
|
||||
```
|
||||
|
||||
Поскольку `start-on-serve: true`, фоновая проверка запустится автоматически. Кеш включён, так что результаты переживут перезапуск. Сайт доступен на `http://0.0.0.0:8080`.
|
||||
|
||||
---
|
||||
|
||||
## Docker
|
||||
|
||||
Удобно запускать сайт в контейнере. Образ `iptvc` уже включает бинарник:
|
||||
|
||||
```yaml title="compose.yml"
|
||||
services:
|
||||
iptvc:
|
||||
image: git.axenov.dev/iptv/iptvc:latest
|
||||
command: [serve]
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./config.yml:/app/config.yml:ro
|
||||
- ./playlists.ini:/app/playlists.ini:ro
|
||||
- ./channels.json:/app/channels.json:ro
|
||||
environment:
|
||||
- CHECK_START_ON_SERVE=true
|
||||
- CACHE_ENABLED=true
|
||||
- CACHE_HOST=keydb
|
||||
- CACHE_PORT=6379
|
||||
|
||||
keydb:
|
||||
image: eqalpha/keydb:latest
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Подробнее об установке образа — в [документации по установке](../install.md).
|
||||
|
||||
---
|
||||
|
||||
## Краткая шпаргалка
|
||||
|
||||
| Задача | Как |
|
||||
| --- | --- |
|
||||
| Запустить сайт | `./iptvc serve` |
|
||||
| С проверкой плейлистов | `./iptvc serve --check` |
|
||||
| На другом порту | `./iptvc serve -p 3000` |
|
||||
| С ini-файлом из другого места | `./iptvc serve -i /path/to/playlists.ini` |
|
||||
| С кешем | `./iptvc serve --check --cache-enabled` |
|
||||
| Один цикл проверки | `./iptvc serve --check --repeat 1` |
|
||||
| Проверять каждые 2 минуты | `./iptvc serve --check --every 120` |
|
||||
| Подробные логи | `./iptvc serve --check --verbose` |
|
||||
|
||||
Полный список параметров — в [справочнике по `config.yml`](../config/config.md), [переменным окружения](../config/env.md) и [команде `serve`](../commands/serve.md).
|
||||
Reference in New Issue
Block a user