wip2
@@ -0,0 +1,387 @@
|
||||
---
|
||||
name: koda-zensical
|
||||
description: Навык, который необходим для работы в этом репозитории и должен закружаться безусловно. Этот навык содержит инструкции, которые позволят правильно писать и форматировать исходные файлы документации.
|
||||
---
|
||||
|
||||
# Документирование
|
||||
|
||||
## Принципы написания документации
|
||||
|
||||
### Язык и стиль
|
||||
|
||||
- Пиши простым и понятным языком
|
||||
- Избегай просторечий и сложных технических терминов без объяснения
|
||||
- Используй активный залог
|
||||
- Обращайся к пользователю на "вы"
|
||||
- Поддерживай единый стиль во всех документах
|
||||
- Не злоупотребляй emoji
|
||||
|
||||
### Примеры
|
||||
|
||||
- Приводи примеры конфигурации
|
||||
- Показывай скриншоты для важных шагов
|
||||
- Добавляй таблицы для сравнения опций
|
||||
|
||||
### Исправление и избегание ошибок
|
||||
|
||||
- Синтаксические и грамматические ошибки должны исправляться в соответствии с правиламии и нормами естественного языка
|
||||
- При изменении структуры документации:
|
||||
- в новый документ следует добавить ссылки на другие релевантные документы или якоря
|
||||
- ссылки на перемещённый или удалённый документ/якорь следует обновить в каждом существующем документе
|
||||
- следует проверять вывод команды `make site` на наличие ошибок и предупреждений компилятора
|
||||
|
||||
## Синтаксис файлов
|
||||
|
||||
В основе документации лежит расширенный markdown.
|
||||
|
||||
Ниже описаны правила оформления и синтаксиса, которые отличаются от стандартного markdown и github-flavoured markdown.
|
||||
|
||||
Расширения синтаксиса предоставляются связкой:
|
||||
|
||||
- `zensical` (документация: <https://zensical.org/docs/>)
|
||||
- `pymdown-extensions` (документация: <https://facelessuser.github.io/pymdown-extensions>)
|
||||
|
||||
Ниже только необходимые и достаточные правила:
|
||||
|
||||
- для качественной документации;
|
||||
- хорошего человеческого восприятия;
|
||||
- корректного формирования документации без ошибок.
|
||||
|
||||
Применение этих подходов необязательно, но требования к каждому требуется соблюдать строго.
|
||||
|
||||
Если приведены ссылки на документацию, можешь использовать их для получения актуальной информации.
|
||||
Там так же могут быть описаные дополнительные приёмы для работы с документами.
|
||||
|
||||
### Frontmatter
|
||||
|
||||
Каждый документ должен начинаться с этого блока метаданных.
|
||||
|
||||
После frontmatter должна быть пустая строка.
|
||||
|
||||
Внутри должен быть валидный yaml.
|
||||
Часто используются следующие опциональные параметры (* — желательны):
|
||||
|
||||
- *`title` — укорочечнное название документа для отображения в навигации (умолчание — заголовок 1 уровня)
|
||||
- *`description` — небольшое осмысленное описание документа (умолчание — пусто)
|
||||
- *`icon` — код иконки для отображения в навигации рядом с названием (умолчание — пусто)
|
||||
- *`tags` — массив ключевых слов (тегов), описывающих документ (умолчание — пусто)
|
||||
- `hide` — массив кодов элементов, которые нужно скрыть на странице документа:
|
||||
- `navigation` — главная навигация (слева)
|
||||
- `toc` — содержание страницы (справа)
|
||||
- `path` — хлебные крошки (сверху)
|
||||
- `status` — статус страницы (добавляет к пункту навигации слева иконку с подсказкой)
|
||||
- `new` — новая информация
|
||||
- `deprecated` — устаревшая информация
|
||||
- `beta` — информация о нестабильном функционале
|
||||
|
||||
Параметр `title` не должен быть равен заголовку первого уровня.
|
||||
В таком случае `title` следует убрать или не добавлять.
|
||||
|
||||
### Заголовки
|
||||
|
||||
На странице должен быть только один заголовок 1 уровня — сразу после Frontmatter.
|
||||
|
||||
До и после каждого заголовка должна быть 1 пустая строка.
|
||||
|
||||
В конце строки заголовка должно быть объявление в формате:
|
||||
`{ id="header-slug" }`
|
||||
|
||||
### Абзацы
|
||||
|
||||
До и после каждого абзаца должна быть 1 пустая строка.
|
||||
|
||||
Каждое предложение внутри абзаца должно быть на новой строке.
|
||||
|
||||
### Списки
|
||||
|
||||
Вложенные уровни отступаются на 4 пробела слева.
|
||||
|
||||
До и после каждого списка должна быть 1 пустая строка.
|
||||
|
||||
Ненумерованные списки начинаются с `-`.
|
||||
|
||||
### Многострочные блоки кода
|
||||
|
||||
До и после каждого блока кода должна быть 1 пустая строка.
|
||||
|
||||
Каждый блок кода в заголовке может иметь атрибуты:
|
||||
|
||||
- `title="..."` — заголовок блока (например, название файла)
|
||||
- `hl_lines="..."` — подсветка срок: номера через пробел и/или диапазоны через `-`
|
||||
- `linenums="N"` — включить нумерацию строк, отсчитывая с указанного числа `N`
|
||||
|
||||
В конце строк внутри блока может быть любое число в формате `#(X)!` — это кликальбельные аннотации, содержимое которых будет взято из ближайшего нумерованного списка.
|
||||
|
||||
Полный пример:
|
||||
|
||||
```yaml title="config.yaml" hl_lines="6 8-10 13 17-20" linenums="1"
|
||||
context:
|
||||
- provider: code
|
||||
# - provider: docs # сломан
|
||||
- provider: diff #(2)!
|
||||
- provider: terminal
|
||||
- provider: problems
|
||||
- provider: folder
|
||||
- provider: codebase
|
||||
params:
|
||||
nFinal: 10
|
||||
# - provider: file
|
||||
# - provider: url
|
||||
# - provider: search #(1)!
|
||||
```
|
||||
|
||||
1. Подсказка 1
|
||||
2. **Подсказка** 2
|
||||
|
||||
### Врезки
|
||||
|
||||
Позволяют акцентировать внимание на ключевых моментах, выделяя блок цветом и иконкой.
|
||||
|
||||
Документация: <https://raw.githubusercontent.com/zensical/docs/master/docs/authoring/admonitions.md>
|
||||
|
||||
Синтаксис:
|
||||
|
||||
```
|
||||
!!! <тип> "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? <тип> "Заголовок разворачиваемой врезки"
|
||||
Содержимое, которое может быть многострочным
|
||||
и свёрнуто по умолчанию, но разворачивается по клику на заголовке
|
||||
|
||||
???+ <тип> "Заголовок сворачиваемой врезки"
|
||||
Содержимое, которое может быть многострочным
|
||||
и развёрнуто по умолчанию, но сворачивается по клику на заголовке
|
||||
```
|
||||
|
||||
Типы, их цвета и пиктограммы:
|
||||
|
||||
| Тип | Цвет | Пиктограмма |
|
||||
| ---------- | ------- | ------------------ |
|
||||
| `note` | #448aff | карандаш в круге |
|
||||
| `abstract` | #00b0ff | планшет для бумаги |
|
||||
| `info` | #00b8d4 | `i` в круге |
|
||||
| `tip` | #00bfa5 | пламя |
|
||||
| `success` | #00c853 | галочка |
|
||||
| `question` | #64dd17 | `?` в круге |
|
||||
| `warning` | #ff9100 | `!` в треугольнике |
|
||||
| `failure` | #ff5252 | крестик |
|
||||
| `danger` | #ff1744 | молния в круге |
|
||||
| `bug` | #f50057 | жук на щите |
|
||||
| `example` | #7c4dff | пробирка |
|
||||
| `quote` | #9e9e9e | двойная кавычка |
|
||||
|
||||
Заголовок может быть пустым, в этом случае:
|
||||
|
||||
- после типа указываются пустые двойные кавычки (иначе подставится название типа с заглавной буквы на английском языке)
|
||||
- содержимое внутри блока обрамлён цветом своего типа
|
||||
|
||||
Если текста внутри врезки нет, отображается только яркий заголовок с иконкой.
|
||||
|
||||
Содержимое врезки отступается минимум на 4 пробела.
|
||||
Содержимое без отступа (в начале строки) находится вне врезки.
|
||||
|
||||
Для содержимого врезки распространяются все те же markdown-правила, включая указанные в этом документе.
|
||||
|
||||
До и после каждой врезки должна быть 1 пустая строка.
|
||||
|
||||
### Сниппеты
|
||||
|
||||
Это переиспользуемые блоки markdown/html, хранящиеся в файлах.
|
||||
|
||||
- Директория: `snippets` в корне проекта
|
||||
- Документация: <https://raw.githubusercontent.com/facelessuser/pymdown-extensions/refs/heads/main/pymdownx/snippets.py>
|
||||
|
||||
Как использовать:
|
||||
|
||||
1. создать файл с директории
|
||||
2. наполнить содержимым
|
||||
3. во всех местах документации вставить:
|
||||
- пустая строка
|
||||
- `--8<-- "filename.md"`
|
||||
- пустая строка
|
||||
4. если файлов несколько, вставить следующим образом:
|
||||
- пустая строка
|
||||
- `--8<--`
|
||||
- `"filename1.md"`
|
||||
- пустая строка
|
||||
- `"filename2.md"`
|
||||
- `--8<--`
|
||||
- пустая строка
|
||||
|
||||
### Иконки
|
||||
|
||||
Каждая иконка определяется своим идентификатором, который делится на две части: код набора и код иконки.
|
||||
|
||||
Внутри frontmatter (параметр `icon`) используется формат: `набор/иконка`
|
||||
|
||||
В тексте документа используется формат: `:набор-иконка:`
|
||||
|
||||
Если иконка в начале строки, пробел ставится только после неё.
|
||||
Если иконка в середине строки, пробелы ставятся до и после неё.
|
||||
Если иконка в конце строки, пробел ставятся только до неё.
|
||||
|
||||
Доступны 4 встроенных набора иконок:
|
||||
|
||||
| Название | Код набора | Ссылка | Путь в проекте |
|
||||
| --------------- | ------------- | ---------------------------------------------- | --------------------------- |
|
||||
| Lucide | `lucide` | <https://lucide.dev/icons/> | - |
|
||||
| Material Design | `material` | <https://pictogrammers.com/library/mdi/> | - |
|
||||
| FontAwesome | `fontawesome` | <https://fontawesome.com/search> | - |
|
||||
| Octicons | `octicons` | <https://primer.style/octicons/> | - |
|
||||
| Simple Icons | `material` | <https://simpleicons.org/> | - |
|
||||
| VSCode Codicons | `vscode` | <https://github.com/microsoft/vscode-codicons> | `./overrides/.icons/vscode` |
|
||||
|
||||
Полный список названий иконок здесь: <https://squidfunk.github.io/mkdocs-material/assets/javascripts/iconsearch_index.json>
|
||||
|
||||
Получить полный список иконок в этих наборах можно прочитав содержимое указанных директорий в проекте.
|
||||
|
||||
### Гриды (карточки)
|
||||
|
||||
Грид позволяет разместить короткие предложения в формате динамических карточек.
|
||||
|
||||
Он выглядит как markdown-список, обрамлённый в `<div>`.
|
||||
До открывающего и после закрывающего тегов должна быть 1 пустая строка.
|
||||
|
||||
Пример простого грида с компактными карточками:
|
||||
|
||||
```
|
||||
<div class="grid cards" markdown>
|
||||
- :fontawesome-brands-html5: Карточка №1
|
||||
- :fontawesome-brands-js: Карточка №2
|
||||
- :fontawesome-brands-css3: Карточка №3
|
||||
- :fontawesome-brands-internet-explorer: Карточка №4
|
||||
</div>
|
||||
```
|
||||
|
||||
Пример грида с многострочными карточками:
|
||||
|
||||
```
|
||||
<div class="grid cards" markdown>
|
||||
- :fontawesome-brands-html5: **Заголовок карточки №1**
|
||||
|
||||
---
|
||||
|
||||
Многострочное содержимое карточки №1
|
||||
|
||||
- :fontawesome-brands-js: **Заголовок карточки №2**
|
||||
|
||||
---
|
||||
|
||||
Многострочное содержимое карточки №2
|
||||
|
||||
- :fontawesome-brands-css3: **Заголовок карточки №3**
|
||||
|
||||
---
|
||||
|
||||
Многострочное содержимое карточки №3
|
||||
|
||||
- :fontawesome-brands-internet-explorer: **Заголовок карточки №4**
|
||||
|
||||
---
|
||||
|
||||
Многострочное содержимое карточки №4
|
||||
</div>
|
||||
```
|
||||
|
||||
### Вкладки (табы)
|
||||
|
||||
Позволяют уместить информацию на одном уровне, не растягивая страницу по высоте.
|
||||
|
||||
Синтаксис:
|
||||
|
||||
```
|
||||
=== "Заголовок вкладки 1"
|
||||
Содержимое вкладки 1
|
||||
|
||||
=== "Заголовок вкладки 2"
|
||||
Содержимое вкладки 2
|
||||
```
|
||||
|
||||
Содержимое вкладки отступается минимум на 4 пробела.
|
||||
Содержимое без отступа (в начале строки) находится вне вкладки.
|
||||
|
||||
Для содержимого вкладки распространяются все те же markdown-правила, включая указанные в этом документе.
|
||||
|
||||
До и после каждого заголовка вкладки должна быть 1 пустая строка.
|
||||
|
||||
После содержимого последней вкладки должна быть 1 пустая строка.
|
||||
|
||||
### Сноски
|
||||
|
||||
Сноска позволяет добавить надстрочный индекс к слову, чтобы вынести пояснения в конец страницы, быстро переместиться к нему по клику на индекс и вернуться обратно.
|
||||
|
||||
Синтаксис:
|
||||
|
||||
```
|
||||
Lorem[^1] ipsum[^2] dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
[^1]: однострочная сноска
|
||||
[^2]:
|
||||
многострочная сноска
|
||||
с отступом 4 пробела слева
|
||||
на каждой строке
|
||||
```
|
||||
|
||||
### Подсказки (тултипы) и аббревиатуры
|
||||
|
||||
Они появляются при наведении мыши на какой-либо элемент на странице документа.
|
||||
|
||||
Пример 1: иконка с подсказкой:
|
||||
`:material-information-outline:{ title="текст подсказки" }`
|
||||
|
||||
Пример 2: ссылка с подсказкой:
|
||||
`[Hover me](https://example.com "I'm a tooltip!")`
|
||||
|
||||
Пример 3: альтернативная ссылка с подсказкой:
|
||||
|
||||
```
|
||||
[Hover me][example]
|
||||
|
||||
[example]: https://example.com "I'm a tooltip!"
|
||||
```
|
||||
|
||||
### Горячие клавиши
|
||||
|
||||
В общем случае, для указания корячих клавиш следует использовать тег `<kbd>`.
|
||||
Примеры: `<kbd>B</kbd>`, `<kbd>Esc</kbd>`
|
||||
|
||||
Для описания комбинаций клавиш следует вставлять между каждой клавишей знак `+`, обрамлённый пробелами.
|
||||
Примеры: `<kbd>Shift</kbd> + <kbd>A</kbd>`, `<kbd>Ctrl</kbd> + <kbd>K</kbd> + <kbd>4</kbd>`
|
||||
|
||||
Для MacOS-специфичных тем вставлять `+` не нужно.
|
||||
Примеры: `<kbd>⌘</kbd><kbd>C</kbd>`, `<kbd>⇧</kbd><kbd>⌘</kbd><kbd>P</kbd>`
|
||||
|
||||
Сопоставление пиктограмм с названиями клавиш (служебных и модификаторов) MacOS:
|
||||
|
||||
- Базовые модификаторы:
|
||||
- `⌘` - `Command` (`Cmd`)
|
||||
- `⌥` - `Option` (`Alt`)
|
||||
- `⌃` - `Control` (`Ctrl`)
|
||||
- `⇧` - `Shift`
|
||||
- `⇪` - `Caps Lock`
|
||||
- Навигация и управление:
|
||||
- `⌫` - `Delete` (Backspace, удаление символа слева)
|
||||
- `⌦` - `Forward Delete` (удаление символа справа, `Fn` + D`elete)
|
||||
- `⏎` - `Return` (`Enter`)
|
||||
- `⌕` - `Enter` на цифровой клавиатуре (в некоторых шрифтах)
|
||||
- `⎋` - `Escape` (`Esc`)
|
||||
- `⇥` - `Tab` (Табуляция)
|
||||
- `⇤` - `Backtab` (`Shift` + `Tab`)
|
||||
- `␣` - `Space` (Пробел)
|
||||
- Перемещение по тексту:
|
||||
- `↖` - `Home` (Начало документа, `Fn` + `←`)
|
||||
- `↘` - `End` (Конец документа, `Fn` + `→`)
|
||||
- `⇞` - `Page Up` (Страница вверх, `Fn` + `↑`)
|
||||
- `⇟` - `Page Down` (Страница вниз, `Fn` + `↓`)
|
||||
- Специальные и системные:
|
||||
- `🌐` / `fn` — Функция (`Fn` / Кнопка смены языка/вызова эмодзи)
|
||||
- `⏏` — `Eject` (Извлечение диска)
|
||||
|
||||
### Кнопки
|
||||
|
||||
- `[Серая кнопка](https://example.com/){ .md-button }`
|
||||
- `[Синяя кнопка](https://example.com/){ .md-button .md-button--primary }`
|
||||
- `[:fontawesome-solid-paper-plane: Кнопка серая с иконкой](https://example.com/){ .md-button }`
|
||||
- `[:fontawesome-solid-paper-plane: Кнопка синяя с иконкой](https://example.com/){ .md-button .md-button--primary }`
|
||||
@@ -0,0 +1,6 @@
|
||||
/.git
|
||||
/.gitea
|
||||
/.gitignore
|
||||
/.cache
|
||||
Makefile
|
||||
.DS_Store
|
||||
@@ -0,0 +1,18 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yaml,yml}]
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
@@ -1,2 +1,4 @@
|
||||
/.cache
|
||||
/site
|
||||
/.cache/
|
||||
/site/
|
||||
/__pycache__/
|
||||
.DS_Store
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
- Всегда используй навык koda-zensical
|
||||
- Всегда перечитывай файлы перед каждым изменением - пользователь уже мог внести изменения
|
||||
- При изменениях структуры проекта всегда актуализируй AGENTS.md
|
||||
- |
|
||||
В структуре навигации файла `zensical.toml` всегда должен присутствовать закомментированный раздел `Debug`.
|
||||
Это отладочные страницы с примерами, которые не должны попасть в итоговую документацию.
|
||||
Этот раздел раскомментируется вручную по необходимости.
|
||||
- |
|
||||
Для отладки используй команду `make site`.
|
||||
В выводе команды могу быть предупреждения и ошибки в следующем формате:
|
||||
|
||||
```
|
||||
Warning: page does not exist
|
||||
╭─[ test.md:695:10 ]
|
||||
│
|
||||
695 │ - [Edit](../edit/how-to-use-it.md) — редактирование кода
|
||||
│ ────────────┬───────────
|
||||
│ ╰───────────── page does not exist
|
||||
─────╯
|
||||
```
|
||||
что означает буквально следующее: "в файле content/test.md в строке 695 в позиции 10 есть ссылка на несуществующую страницу."
|
||||
Эти предупреждения надо всегда исправлять.
|
||||
|
||||
- При изменениях структуры проекта и только при корректной сборке (без предупреждений и ошибок) всегда актуализируй `./AGENTS.md`
|
||||
- При доработке или расширении функционала этого проекта или синтаксиса всегда актуализируй скилл `./.agents/skills/koda-zensical`
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"0x10.mkdocs-material-preview"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.md": "python-markdown"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Живой предпросмотр (localhost:8000)",
|
||||
"type": "shell",
|
||||
"command": "make live"
|
||||
},
|
||||
{
|
||||
"label": "Собрать статический сайт (./site)",
|
||||
"type": "shell",
|
||||
"command": "make site"
|
||||
},
|
||||
{
|
||||
"label": "Собрать docker-образ со стат. сайтом",
|
||||
"type": "shell",
|
||||
"command": "make image"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,19 @@
|
||||
FROM squidfunk/mkdocs-material AS builder
|
||||
FROM zensical/zensical:latest AS builder
|
||||
ENV PYTHONPATH=/docs
|
||||
COPY . /docs
|
||||
RUN mkdocs build
|
||||
RUN zensical build --clean
|
||||
|
||||
FROM nginx:alpine AS iptv-docs
|
||||
|
||||
LABEL org.opencontainers.image.title="IPTV Checker"
|
||||
LABEL org.opencontainers.image.description="Documentation for our services and products"
|
||||
LABEL org.opencontainers.image.authors="Anthony Axenov <anthonyaxenov@gmail.com>"
|
||||
LABEL org.opencontainers.image.url="https://m3u.su"
|
||||
LABEL org.opencontainers.image.vendor="Anthony Axenov"
|
||||
LABEL org.opencontainers.image.documentation="https://m3u.su/docs"
|
||||
LABEL org.opencontainers.image.licenses="MIT"
|
||||
LABEL org.opencontainers.image.source="https://git.axenov.dev/IPTV/docs"
|
||||
|
||||
COPY --from=builder /docs/site /usr/share/nginx/html
|
||||
WORKDIR /usr/share/nginx/html
|
||||
USER root
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Антон Аксенов (Anthony Axenov)
|
||||
Copyright (c) 2025-2026 Антон Аксенов (Anthony Axenov)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,49 +1,54 @@
|
||||
## image: Run mkdocs with live-reloading (localhost:3000)
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: live site image push run help
|
||||
|
||||
## live = Run zensical with live-reloading on http://localhost:8000
|
||||
live:
|
||||
@echo "Wait until container starts and open http://localhost:3000 to see live preview"
|
||||
@docker run \
|
||||
--pull always \
|
||||
@echo "*** Wait until container starts and open http://localhost:8000 to see live preview"
|
||||
@docker stop iptv-docs-dev 2>/dev/null; \
|
||||
docker run \
|
||||
--rm \
|
||||
--interactive \
|
||||
--tty \
|
||||
--publish 3000:8000 \
|
||||
--env PYTHONPATH=/docs \
|
||||
--publish 8000:8000 \
|
||||
--volume ${PWD}:/docs \
|
||||
--name iptv-docs-dev \
|
||||
squidfunk/mkdocs-material:9.6.20
|
||||
zensical/zensical:latest
|
||||
|
||||
## image: Build local static site
|
||||
## site = Build a local static site
|
||||
site:
|
||||
@echo "Wait until mkdocs finish"
|
||||
@docker run \
|
||||
@echo "*** Wait until zensical finish"
|
||||
@docker stop iptv-docs-dev 2>/dev/null; \
|
||||
docker run \
|
||||
--pull always \
|
||||
--rm \
|
||||
--interactive \
|
||||
--tty \
|
||||
--env PYTHONPATH=/docs \
|
||||
--volume ${PWD}:/docs \
|
||||
--name iptv-docs-dev \
|
||||
squidfunk/mkdocs-material:9.6.20 build
|
||||
zensical/zensical:latest \
|
||||
build \
|
||||
--clean
|
||||
|
||||
## image: Build docker image
|
||||
## image = Build a docker image
|
||||
image:
|
||||
@docker build \
|
||||
--tag iptv-docs:latest \
|
||||
--tag git.axenov.dev/iptv/iptv-docs:latest \
|
||||
.
|
||||
@docker build --tag git.axenov.dev/iptv/iptv-docs:latest:latest .
|
||||
|
||||
## push: Push docker image to registry
|
||||
push:
|
||||
@docker push git.axenov.dev/iptv/iptv-docs:latest
|
||||
|
||||
## run: Run docker image (localhost:3001)
|
||||
## run = Run docker container from image built with `make image` on http://localhost:8001
|
||||
run:
|
||||
@echo "Wait until container starts and open http://localhost:3001 to see ready static website"
|
||||
@docker run \
|
||||
@echo "*** Wait until container starts and open http://localhost:8001 to see ready static website"
|
||||
@docker stop iptv-docs 2>/dev/null; \
|
||||
docker run \
|
||||
--rm \
|
||||
--publish 3001:80 \
|
||||
--publish 8001:80 \
|
||||
--name iptv-docs \
|
||||
git.axenov.dev/iptv/iptv-docs:latest
|
||||
git.axenov.dev/iptv/iptv-docs:latest:latest
|
||||
|
||||
## help: Show this message and exit
|
||||
# push = Push docker image built with `make image` to git.axenov.dev
|
||||
push:
|
||||
@docker login git.axenov.dev; \
|
||||
docker push git.axenov.dev/iptv/iptv-docs:latest:latest
|
||||
|
||||
## help = Show this message and exit (default)
|
||||
help: Makefile
|
||||
@echo "Available recipes:"
|
||||
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
|
||||
@sed -n 's/^##/ /p' $< | column -t -s '='
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Документация m3u.su
|
||||
# Документация iptvc
|
||||
|
||||
Как работать с документацией: [src/dev/docs.md](src/dev/docs.md)
|
||||
Как работать с документацией: [content/dev/docs.md](content/dev/docs.md)
|
||||
|
||||
## Лицензия
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
.md-typeset .yoomoney > .admonition-title,
|
||||
.md-typeset .yoomoney > summary {
|
||||
background-color: rgba(113, 47, 244, 0.1);
|
||||
/* background-color: rgba(113, 47, 244, 0.1); */
|
||||
}
|
||||
.md-typeset .yoomoney > .admonition-title::before,
|
||||
.md-typeset .yoomoney > summary::before {
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
.md-typeset .boosty > .admonition-title,
|
||||
.md-typeset .boosty > summary {
|
||||
background-color: rgba(241, 95, 44, 0.1);
|
||||
/* background-color: rgba(241, 95, 44, 0.1); */
|
||||
}
|
||||
.md-typeset .boosty > .admonition-title::before,
|
||||
.md-typeset .boosty > summary::before {
|
||||
@@ -111,3 +111,9 @@ main ol li {
|
||||
.icon.offline {
|
||||
color: rgb(220, 53, 69);
|
||||
}
|
||||
|
||||
|
||||
.md-typeset .md-button--primary {
|
||||
background: var(--md-accent-fg-color--transparent);
|
||||
color: var(--md-accent-fg-color);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -8,7 +8,7 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
!!! danger "Я не гарантирую корректность и актуальность плейлистов, которые ты увидишь на сайте, как и корректность результатов их проверки."
|
||||
После прочтения этой страницы ты поймёшь почему.
|
||||
|
||||
Плейлисты [проверяются автоматически](../iptvc/index.md) с некоей периодичностью.
|
||||
Плейлисты [проверяются автоматически](../iptvc/overview.md) с некоей периодичностью.
|
||||
|
||||
Хотя я и стараюсь улучшать качество проверок, но всё же рекомендую проверять желаемые плейлисты самостоятельно вручную, ибо нет никаких гарантий:
|
||||
|
||||
@@ -17,10 +17,9 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
* он может работать, но проверка заврешена из-за какой-то технической ошибки;
|
||||
* он уже может не работать, но результаты последней проверки показывают обратное;
|
||||
* что транслируемый контент соответствует заявленным названиям;
|
||||
* что сейчас или через X времени там не окажется [заглушка](../faq.md#заглушка).
|
||||
* что сейчас или через X времени там не окажется [заглушка](faq.md#заглушка).
|
||||
|
||||
<a id="playlists"></a>
|
||||
## Статусы плейлистов
|
||||
## Статусы плейлистов { id="playlists" }
|
||||
|
||||
Каждый плейлист может быть в одном из трёх статусов:
|
||||
|
||||
@@ -39,8 +38,7 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
Независимо от статуса плейлиста на сайте, его можно добавить в свой плеер по "Ссылке для ТВ" и проверить самостоятельно.
|
||||
Проверка плейлиста не влияет на его работоспособность.
|
||||
|
||||
<a id="extra"></a>
|
||||
### Дополнительные возможности
|
||||
### Дополнительные возможности { id="extra" }
|
||||
|
||||
Если плейлист <span class="badge online">online</span> (успешно проверен), то у него могут быть дополнительные значки:
|
||||
|
||||
@@ -58,16 +56,15 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
!!! info "Обрати внимание"
|
||||
1. Пропорции рабочих и нерабочих каналов в плейлистах могут меняться от проверки к проверке.
|
||||
Это нормально, таковы технические особенности проверки.
|
||||
2. Работа архива и программы передач зависит от выбранного [плеера](players.md).
|
||||
2. Работа архива и программы передач зависит от выбранного [плеера](../common/players.md).
|
||||
Некоторые это просто не поддерживают.
|
||||
|
||||
<a id="channels"></a>
|
||||
## Статусы каналов
|
||||
## Статусы каналов { id="channels" }
|
||||
|
||||
Каждый канал в любом плейлисте может быть в одном из трёх статусов:
|
||||
|
||||
* <span class="icon online"><ion-icon name="radio-button-on-outline"></ion-icon></span> — ***Возможно*, канал работает**
|
||||
Но там может транслироваться какая-нибудь [заглушка](../faq.md#заглушка) (например, от [Wink](../faq.md#wink)) или другой канал.
|
||||
Но там может транслироваться какая-нибудь [заглушка](faq.md#заглушка) (например, от [Wink](faq.md#wink)) или другой канал.
|
||||
|
||||
* <span class="icon offline"><ion-icon name="radio-button-on-outline"></ion-icon></span> — ***Возможно*, канал не работает**
|
||||
Чем больше таких каналов в плейлисте, тем сложнее будет листать плейлист в плеере или на ТВ.
|
||||
@@ -82,14 +79,13 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
* <span class="badge adult">18+</span> — **Канал для взрослых**
|
||||
Читай ниже.
|
||||
|
||||
<a id="adult"></a>
|
||||
## Контент для взрослых
|
||||
## Контент для взрослых { id="adult" }
|
||||
|
||||
Это откровенно порнографический, эротический или другой контент, неприемлемый для детской психики (например, жанровые каналы с фильмами ужасов).
|
||||
|
||||
Если при проверке плейлиста обнаружен хотя бы один канал для взрослых, то этот канал и весь плейлист помечается значком <span class="badge adult">18+</span>.
|
||||
|
||||
Такие каналы определяются благодаря правилам, описанным в файле [channels.json](../formats/channels.md).
|
||||
Такие каналы определяются благодаря правилам, описанным в файле [channels.json](../common/formats/channels.md).
|
||||
Они применяются к названиям каналов и их атрибутам (`tvg-id`, `tvg-name`), которые описывают канал в плейлисте.
|
||||
|
||||
Для каналов со взрослым контентом применяется тег `adult`.
|
||||
@@ -97,7 +93,7 @@ tags: ["статусы", "плейлисты", "каналы", "iptvc"]
|
||||
!!! warning "Обрати внимание"
|
||||
Далеко не все каналы могут быть помечены таким тегом.
|
||||
Хотя набор правил для тегов очень богат, но невозможно угадать все каналы с приемлемой точностью.
|
||||
Почему — читай [здесь](../formats/channels.md#warnings).
|
||||
Почему — читай [здесь](../common/formats/channels.md#warnings).
|
||||
|
||||
---
|
||||
|
||||
@@ -46,8 +46,8 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
## Откуда берутся логотипы каналов и программы передач?
|
||||
|
||||
Всё это (не) [указывается](formats/m3u.md#tvg-logo) внутри плейлиста его авторами.
|
||||
Но в некоторых [плеерах](common/players.md) можно вручную указывать программу передач (см. ниже).
|
||||
Всё это (не) [указывается](../common/formats/m3u.md#tvg-logo) внутри плейлиста его авторами.
|
||||
Но в некоторых [плеерах](../common/players.md) можно вручную указывать программу передач (см. ниже).
|
||||
|
||||
## У канала нет логотипа!
|
||||
|
||||
@@ -55,7 +55,7 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
## У **канала** нет программы передач (EPG), что делать?
|
||||
|
||||
Фига в том, что EPG может быть и [указан](formats/m3u.md#url-tvg) в плейлисте, но у конкретного канала могут быть указаны некорректные [`tvg-id`](formats/m3u.md#tvg-id) или [`tvg-name`](formats/m3u.md#tvg-name).
|
||||
Фига в том, что EPG может быть и [указан](../common/formats/m3u.md#url-tvg) в плейлисте, но у конкретного канала могут быть указаны некорректные [`tvg-id`](../common/formats/m3u.md#tvg-id) или [`tvg-name`](../common/formats/m3u.md#tvg-name).
|
||||
Может, его дёрнули из другого листа и не подогнали под другую EPG.
|
||||
|
||||
Так что вариантов масса:
|
||||
@@ -74,18 +74,17 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
* не все плееры вообще поддерживают работу с телепрограммой;
|
||||
* в плейлисте она просто может не быть указана.
|
||||
|
||||
Но если [плеер](common/players.md) позволяет, можно указать ссылку на сторонную телепрограмму.
|
||||
Но если [плеер](../common/players.md) позволяет, можно указать ссылку на сторонную телепрограмму.
|
||||
|
||||
И это целое дело.
|
||||
Надо чтобы совпадали [`tvg-id`](formats/m3u.md#tvg-id) или [`tvg-name`](formats/m3u.md#tvg-name) каналов с теми, которые указываются в EPG.
|
||||
Надо чтобы совпадали [`tvg-id`](../common/formats/m3u.md#tvg-id) или [`tvg-name`](../common/formats/m3u.md#tvg-name) каналов с теми, которые указываются в EPG.
|
||||
Так что не всякая телепрограмма подойдёт, не ко всякому плейлисту и не ко всем каналам.
|
||||
Надо подбирать и то, и то.
|
||||
|
||||
<a id="epg"></a>
|
||||
## А где взять программу передач (EPG)?
|
||||
## А где взять программу передач (EPG)? { id="epg" }
|
||||
|
||||
1. Из самого плейлиста.
|
||||
Часто в атрибут [`url-tvg`](formats/m3u.md#url-tvg) тега `#EXTM3U` указывают одну или две ссылки на EPG, разделяя их `;`.
|
||||
Часто в атрибут [`url-tvg`](../common/formats/m3u.md#url-tvg) тега `#EXTM3U` указывают одну или две ссылки на EPG, разделяя их `;`.
|
||||
Их можно использовать отдельно, например, если плеер не может корректно обработать такое значение.
|
||||
|
||||
2. Взять одну из этих ссылок:
|
||||
@@ -115,13 +114,13 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
## Почему на сайте плейлист онлайн, но в нём 0 каналов?
|
||||
|
||||
[Тебе сюда](common/checks.md#playlists).
|
||||
[Тебе сюда](checks.md#playlists).
|
||||
|
||||
## Почему на сайте плейлист онлайн, но у меня он не работает?
|
||||
|
||||
Что значит "не работает"?
|
||||
|
||||
* Ты уверен, что ссылка в [правильном формате](common/details.md#shortlink)?
|
||||
* Ты уверен, что ссылка в [правильном формате](../iptvc/site/details.md#shortlink)?
|
||||
* Ты уверен, что у тебя нормальное интернет-соединение?
|
||||
* Плеер показывает какую-то ошибку при добавлении плейлиста?
|
||||
* Плейлист добавляется по ссылке, но каналы не загружаются или плеер зависает?
|
||||
@@ -129,12 +128,12 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
* А есть скриншоты? Логи? Тексты ошибок?
|
||||
|
||||
Попробуй погуглить проблему с конкретным плеером, может ты не один с такой проблемой.
|
||||
Или [узнать в чате](tg/chat.md).
|
||||
Или [узнать в чате](../tg/chat.md).
|
||||
|
||||
Но вообще, это зависит от:
|
||||
|
||||
* автора плейлиста (дохлые каналы почти всегда есть даже в свежайших листах, но если лист не обновлялся год, что ты вряд-ли узнаешь, то рабочих каналов там не ищи);
|
||||
* твоего [плеера](common/players.md) (видеотрансляции могут использовать кодек, который просто не поддерживается плеером);
|
||||
* твоего [плеера](../common/players.md) (видеотрансляции могут использовать кодек, который просто не поддерживается плеером);
|
||||
* ширины твоего интернет-канала (не надо пытаться врубать FHD/4K трансляции с мобильного интернета на самом дешёвом тарифе в лесу);
|
||||
* ретроградности Меркурия и магнитных бурь (а вдруг);
|
||||
* настроек твоей сети, твоего интернет-провайдера, VPN (подумай хорошенько, хочешь ли ты смотреть российские каналы из РФ через Уганду или США);
|
||||
@@ -154,13 +153,13 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
Короткие коды плейлистов могут меняться, поэтому вполне может произойти внезапная подмена одного другим, однако это происходит крайне редко.
|
||||
|
||||
Плюс читай про доверие [результатам проверки](common/checks.md).
|
||||
Плюс читай про доверие [результатам проверки](checks.md).
|
||||
|
||||
## В плейлистах порнуха!
|
||||
|
||||
Да, в плейлистах порнуха.
|
||||
|
||||
Это [явно помечается](common/checks.md#adult) везде, где это технически возможно.
|
||||
Это [явно помечается](checks.md#adult) везде, где это технически возможно.
|
||||
Смотри с удовольствием сколько хочешь, всё для тебя.
|
||||
|
||||
Или без удовольствия.
|
||||
@@ -186,13 +185,12 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
Если есть кандидаты на добавление, то читай ниже.
|
||||
|
||||
<a id="автообновляемый"></a>
|
||||
## Что значит автообновляемый плейлист?
|
||||
## Что значит автообновляемый плейлист? { id="автообновляемый" }
|
||||
|
||||
Например, ты на своём компе:
|
||||
|
||||
* открываешь любой текстовый редактор;
|
||||
* оформляешь текст в формате [m3u](formats/m3u.md);
|
||||
* оформляешь текст в формате [m3u](../common/formats/m3u.md);
|
||||
* сохраняешь в файл `pls.m3u`.
|
||||
|
||||
Получился плейлист `pls.m3u`.
|
||||
@@ -253,32 +251,30 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
Нет, и не планируется.
|
||||
|
||||
Ищи [плеер](common/players.md) и добавляй плейлист туда по ссылке.
|
||||
Ищи [плеер](../common/players.md) и добавляй плейлист туда по ссылке.
|
||||
|
||||
<a id="заглушка"></a>
|
||||
## На канале отображается заглушка
|
||||
## На канале отображается заглушка { id="заглушка" }
|
||||
|
||||
<a id="заглушка1"></a>
|
||||
### Просят денег и/или подписку
|
||||
### Просят денег и/или подписку { id="заглушка1" }
|
||||
|
||||
??? quote "[Скриншот] Уважаемый клиент! Для возобновления просмотра Вам необходимо использовать не более 2 устройств"
|
||||

|
||||

|
||||
> Уважаемый клиент! Для возобновления просмотра Вам необходимо использовать не более 2 устройств.
|
||||
> Обратитесь к поставщику контента для уточнения.
|
||||
|
||||
??? quote "[Скриншот] Ваша подписка не активна"
|
||||

|
||||

|
||||
> Ваша подписка не активна
|
||||
> Your subscription is not active
|
||||
|
||||
??? quote "[Скриншот] Мы обнаружили систематическое нарушение правил использования нашего сервиса"
|
||||

|
||||

|
||||
> Мы обнаружили систематическое нарушение правил использования нашего сервиса и заблокировали возможность просмотра контента.
|
||||
> Для возобновления просмотра необходимо сменить OTTID в личном кабинете, и обновить плейлисты на ваших устройствах.
|
||||
> Если вы считаете, что произошла какая-то ошибка - пожалуйста, обратитесь в техподдержку.
|
||||
|
||||
??? quote "[Скриншот] Вы превысили разрешённое количество одновременных поджключений"
|
||||

|
||||

|
||||
> Вы превысили разрешённое количество одновременных подключений
|
||||
> Для возобновления просмотра ограничьте количество подключённых устройств
|
||||
|
||||
@@ -296,15 +292,14 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
Этот плейлист — главный кандидат на удаление с сайта.
|
||||
|
||||
<a id="wink"></a>
|
||||
### Wink
|
||||
### Wink { id="wink" }
|
||||
|
||||
??? quote "[Скриншот] Просмотр ТВ-каналов, фильмов и сериалов доступен только в официальных приложениях Wink и на территории России"
|
||||

|
||||

|
||||
> Просмотр ТВ-каналов, фильмов и сериалов доступен только в официальных приложениях Wink и на территории России
|
||||
|
||||
??? quote "[Скриншот] Wink ещё не показывает видео на этой территории"
|
||||

|
||||

|
||||
> Wink ещё не показывает видео на этой территории
|
||||
|
||||
**Решение 1:** купить подписку Wink и использовать официальные приложения.
|
||||
@@ -313,7 +308,7 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
||||
|
||||
**Решение 3:** если IP не российский, то сделать его российским (любыми способами).
|
||||
|
||||
**Решение 4:** использовать [плеер](common/players.md), который позволяет указать **User-Agent**, и вставить туда какой-нибудь из этих:
|
||||
**Решение 4:** использовать [плеер](../common/players.md), который позволяет указать **User-Agent**, и вставить туда какой-нибудь из этих:
|
||||
|
||||
```
|
||||
Mozilla/5.0 WINK/1.28.2 (AndroidTV/9) HlsWinkPlayer
|
||||
@@ -1,19 +1,18 @@
|
||||
---
|
||||
icon: material/home
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# :material-home: Введение
|
||||
# :material-home: Об агрегаторе m3u.su
|
||||
|
||||
Сервис предназначен для централизованного сбора ссылок на публичные IPTV-плейлисты, которые находятся в открытом доступе.
|
||||
Этот сервис предназначен для централизованного сбора ссылок на публичные IPTV-плейлисты, которые находятся в открытом доступе.
|
||||
Они отбираются вручную и периодически проверяются автоматически.
|
||||
|
||||
!!! info "Все необходимые адреса"
|
||||
**Веб-сайт:** [m3u.su](https://m3u.su)
|
||||
**Документация:** [m3u.su/docs](https://m3u.su/docs)
|
||||
Документация: [m3u.su/docs](https://m3u.su/docs)
|
||||
Исходный код: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV)
|
||||
Telegram-канал: [@iptv_aggregator](https://t.me/iptv_aggregator)
|
||||
Обсуждение: [@iptv_aggregator_chat](https://t.me/iptv_aggregator_chat)
|
||||
Бот: [@iptv_aggregator_bot](https://t.me/iptv_aggregator_bot)
|
||||
|
||||
Далеко не все пользователи, желающие использовать цифровое ТВ, могут позволить себе подключение IPTV у своего провайдера или поставщиков контента.
|
||||
|
||||
@@ -62,7 +61,7 @@ icon: material/home
|
||||
Автор не зарабатывает на проекте и не собирается.
|
||||
Всё, что отображается на сайте, сделано бесплатно и на энтузиазме.
|
||||
|
||||
Но ты можешь сделать [добровольное пожертвование](support.md), которое поможет мне компенсировать затраты на поддержку и техническое развитие проекта.
|
||||
Но ты можешь сделать [добровольное пожертвование](../common/support.md), которое поможет мне компенсировать затраты на поддержку и техническое развитие проекта.
|
||||
|
||||
## Условия, гарантии, обязательства и последствия
|
||||
|
||||
@@ -16,4 +16,3 @@ tags: ["статусы", "плейлисты"]
|
||||
В основном, в плейлистах именно трансляции телеканалов, но может быть и медиатека: просто список каких-то (мульт)фильмов и записи телепередач, находящихся на чужих дисках (как если бы вы сами составили плейлист, например, с музыкой).
|
||||
|
||||
!!! danger "Плейлисты, нарушающие законодательство, удаляются с сайта окончательно по факту обращения от правообладателя."
|
||||
И претензии на этот счёт не принимаются.
|
||||
@@ -8,21 +8,21 @@ tags: ["сайт"]
|
||||
Так выглядит статусная страница сервиса.
|
||||
Попасть на неё можно по ссылке "[Аптайм](https://status.m3u.su)" в шапке сайта.
|
||||
|
||||

|
||||

|
||||
|
||||
Здесь отображается состояние компонентов сервиса:
|
||||
|
||||
* веб-интерфейс (то, что открывается в браузере);
|
||||
* чекер (фоновая проверка плейлистов с помощью [iptvc](iptvc/index.md));
|
||||
* чекер (фоновая проверка плейлистов с помощью [iptvc](../iptvc/overview.md));
|
||||
* кэш (база данных с временными данными о результатах проверки плейлистов).
|
||||
|
||||
Шкалы движутся во времени справа налево.
|
||||
Они должны быть зелёными, а статус компонента должен быть «Healthy».
|
||||
Каждое деление на шкале приблизительно равно 10 минутам между проверками.
|
||||
|
||||
Можно нажать на незвание сервиса и посмотреть детальную информацию:
|
||||
Можно нажать на название сервиса и посмотреть детальную информацию:
|
||||
|
||||

|
||||

|
||||
|
||||
Если на шкале появляется красное деление, значит был кратковременный сбой.
|
||||
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
@@ -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
|
||||
```
|
||||
@@ -27,7 +27,7 @@ icon: material/book-open-page-variant-outline
|
||||
4. справа — содержание конкретной страницы.
|
||||
|
||||
??? info end "На мобильниках содержание страницы спрятано за этой кнопкой в боковом меню:"
|
||||

|
||||

|
||||
|
||||
## Связанные статьи
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
title: channels.json
|
||||
icon: material/code-json
|
||||
tags: ["iptvc", "теги", "каналы"]
|
||||
---
|
||||
@@ -38,8 +39,7 @@ tags: ["iptvc", "теги", "каналы"]
|
||||
|
||||
Каналы сопоставляются в нижнем регистре.
|
||||
|
||||
<a id="warnings"></a>
|
||||
## Рекомендации и предостережения
|
||||
## Рекомендации и предостережения { id="warnings" }
|
||||
|
||||
1. Если хочешь написать новое правило, будь осторожен с регулярками.
|
||||
Старайся не охватывать несколько каналов сразу.
|
||||
@@ -58,8 +58,7 @@ tags: ["iptvc", "теги", "каналы"]
|
||||
Некоторые каналы имеют `tvg-name`.
|
||||
Все три параметра могут оказаться на кириллице.
|
||||
|
||||
<a id="доступные-теги">
|
||||
## Доступные теги
|
||||
## Доступные теги { id="доступные-теги" }
|
||||
|
||||
| Ключевое слово | Описание |
|
||||
| -------------- | ----------------------------------------------------------- |
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
title: "*.m3u (*.m3u8)"
|
||||
icon: material/playlist-play
|
||||
tags: ["плейлисты", "каналы"]
|
||||
---
|
||||
@@ -15,6 +16,7 @@ tags: ["плейлисты", "каналы"]
|
||||
После директив с новой строки указывается ссылка на канал (или путь к файлу).
|
||||
|
||||
В свою чередь, по этой ссылке может быть:
|
||||
|
||||
* либо текстовое представление контента в формате m3u/m3u8/XMLTV/MPD с описанием непосредственно участки трансляции;
|
||||
* либо непосредственно сама потоковая трансляция mp4 или т. п.
|
||||
|
||||
@@ -39,30 +41,25 @@ http://example.com/play-bbc.m3u
|
||||
http://example.com/play-am.m3u8
|
||||
```
|
||||
|
||||
<a id="EXTM3U"></a>
|
||||
### Директива `#EXTM3U`
|
||||
### Директива `#EXTM3U` { id="EXTM3U" }
|
||||
|
||||
Заголовок файла (обязателен).
|
||||
|
||||
<a id="url-tvg"></a>
|
||||
#### Атрибут `url-tvg` (он же `x-tvg-url`)
|
||||
#### Атрибут `url-tvg` (он же `x-tvg-url`) { id="url-tvg" }
|
||||
|
||||
Ссылка программу передач в формате `*.xml` или `*.xml.gz`.
|
||||
|
||||
<a id="catchup"></a>
|
||||
#### Атрибуты `catchup*`
|
||||
#### Атрибуты `catchup*` { id="catchup" }
|
||||
|
||||
Читай здесь: [Архив телепрограмм (SS IPTV)](https://ss-iptv.com/ru/operators/catchup)
|
||||
|
||||
<a id="EXTGRP"></a>
|
||||
### Директива `#EXTGRP`
|
||||
### Директива `#EXTGRP` { id="EXTGRP" }
|
||||
|
||||
Название группы, к которой относится контент (звуковая дорожка или канал).
|
||||
|
||||
Указывается в формате `#EXTGRP:XXX`, где: `XXX` — название группы.
|
||||
|
||||
<a id="EXTINF"></a>
|
||||
### Директива `#EXTINF`
|
||||
### Директива `#EXTINF` { id="EXTINF" }
|
||||
|
||||
Описывает контент (звуковую дорожку или канал).
|
||||
|
||||
@@ -71,46 +68,38 @@ http://example.com/play-am.m3u8
|
||||
* `YYY` — атрибуты (см. ниже);
|
||||
* `ZZZ` — название контента;
|
||||
|
||||
<a id="tvg-shift"></a>
|
||||
#### Атрибут `tvg-shift`
|
||||
#### Атрибут `tvg-shift` { id="tvg-shift" }
|
||||
|
||||
Cмещение телепрограммы в часах относительно указанного в программе.
|
||||
|
||||
<a id="tvg-id"></a>
|
||||
#### Атрибуты `tvg-id` и `tvg-name` { id="tvg-id" }
|
||||
<a id="tvg-name"></a>
|
||||
#### Атрибуты `tvg-id` и `tvg-name`
|
||||
|
||||
Идентификатор телепрограммы канала.
|
||||
По нему телепрограмма привязывается к трансляции с учётом смещения времени.
|
||||
|
||||
<a id="tvg-logo"></a>
|
||||
#### Атрибут `tvg-logo`
|
||||
#### Атрибут `tvg-logo` { id="tvg-logo" }
|
||||
|
||||
Ссылка на логотип канала.
|
||||
|
||||
<a id="tvg-country"></a>
|
||||
#### Атрибут `tvg-country`
|
||||
#### Атрибут `tvg-country` { id="tvg-country" }
|
||||
|
||||
Код Alpha-2 страны вещания согласно ISO 3166-1 или ОКСМ.
|
||||
|
||||
<a id="tvg-language"></a>
|
||||
#### Атрибут `tvg-language`
|
||||
#### Атрибут `tvg-language` { id="tvg-language" }
|
||||
|
||||
Название языка телепередачи согласно ISO 639-2.
|
||||
|
||||
<a id="group-title"></a>
|
||||
#### Атрибут `group-title`
|
||||
#### Атрибут `group-title` { id="group-title" }
|
||||
|
||||
Название группы.
|
||||
По функционалу идентичен директиве `#EXTGRP`.
|
||||
|
||||
<a id="user-agent"></a>
|
||||
#### Атрибут `user-agent`
|
||||
#### Атрибут `user-agent` { id="user-agent" }
|
||||
|
||||
Значение заголовка `User-Agent` для обращения к контенту по http.
|
||||
|
||||
<a id="audio-track"></a>
|
||||
#### Атрибут `audio-track`
|
||||
#### Атрибут `audio-track` { id="audio-track" }
|
||||
|
||||
Языковой код (ISO 639-2) аудио дорожки канала, например: "eng,rus".
|
||||
|
||||
@@ -118,15 +107,13 @@ Cмещение телепрограммы в часах относительн
|
||||
|
||||
Дорожкой по умолчанию устанавливается первая указанная в списке.
|
||||
|
||||
<a id="aspect-ratio"></a>
|
||||
#### Атрибут `aspect-ratio`
|
||||
#### Атрибут `aspect-ratio` { id="aspect-ratio" }
|
||||
|
||||
Определяет пропорции экрана (может быть недоступно для некоторых моделей телевизоров).
|
||||
|
||||
Допустимые значения: 16:9, 3:2, 4:3, 1,85:1, 2,39:1 (наиболее распространенное значение для фильмов)
|
||||
|
||||
<a id="EXTVLCOPT"></a>
|
||||
### Директива `#EXTVLCOPT`
|
||||
### Директива `#EXTVLCOPT` { id="EXTVLCOPT" }
|
||||
|
||||
Специфична для VLC Player.
|
||||
Директив может быть множество для одной дорожки (канала).
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
title: playlists.ini
|
||||
icon: material/code-brackets
|
||||
tags: ["плейлисты"]
|
||||
---
|
||||
@@ -23,7 +24,7 @@ src = 'https://example.com/super-duper-playlist'
|
||||
Для значений можно (не) использовать 'одинарные' или "двойные" кавычки.
|
||||
Ради единообразия рекомендуется использовать 'одинарные'.
|
||||
|
||||
## `code`
|
||||
## `code` { id="code" }
|
||||
|
||||
Код плейлиста в рамках этого конфига (**обязательно**).
|
||||
|
||||
@@ -35,23 +36,23 @@ src = 'https://example.com/super-duper-playlist'
|
||||
Для удобства ввода с пульта, код рекомендуется задавать числом или короткой строкой без пробелов и др. спецсимволов.
|
||||
Чем короче, тем лучше.
|
||||
|
||||
## `name`
|
||||
## `name` { id="name" }
|
||||
|
||||
Название плейлиста (необязательно).
|
||||
|
||||
По умолчанию: `Playlist #<code>`.
|
||||
|
||||
## `desc`
|
||||
## `desc` { id="desc" }
|
||||
|
||||
Краткое описание из источника или от себя (необязательно).
|
||||
|
||||
По умолчанию: пусто.
|
||||
|
||||
## `pls`
|
||||
## `pls` { id="pls" }
|
||||
|
||||
Прямая ссылка на m3u/m3u8 плейлист (**обязательно**).
|
||||
|
||||
## `src`
|
||||
## `src` { id="src" }
|
||||
|
||||
Ссылка на источник (страницу сайта), откуда был взят плейлист (необязательно).
|
||||
|
||||
@@ -6,11 +6,11 @@ hide: [toc]
|
||||
# Общая информация
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
- [:material-cogs: Как работает сервис](how-it-works.md)
|
||||
- [:material-file-eye-outline: Как отбираются плейлисты](selection.md)
|
||||
- [:material-file-refresh-outline: Проверки и статусы](checks.md)
|
||||
- [:fontawesome-solid-list-check: Список плейлистов](list.md)
|
||||
- [:material-table-eye: Страница плейлиста](details.md)
|
||||
- [:material-television-play: Как подключить плейлист](connect.md)
|
||||
- [:material-cogs: Как работает сервис](../aggregator/overview.md)
|
||||
- [:material-file-eye-outline: Как отбираются плейлисты](../aggregator/selection.md)
|
||||
- [:material-file-refresh-outline: Проверки и статусы](../aggregator/checks.md)
|
||||
- [:fontawesome-solid-list-check: Список плейлистов](../iptvc/site/list.md)
|
||||
- [:material-table-eye: Страница плейлиста](../iptvc/site/details.md)
|
||||
- [:material-television-play: Как подключить плейлист](../iptvc/site/connect.md)
|
||||
- [:material-multimedia: IPTV плееры](players.md)
|
||||
</div>
|
||||
@@ -15,7 +15,7 @@ tags: ["плееры"]
|
||||
Обращайся к содержанию справа для быстрой навигации.
|
||||
|
||||
!!! info "Здесь не хватает очень много подробностей"
|
||||
Если ты имел дело с каким-то плеером, знаешь как его настроить или какие-то другие детали, я прошу тебя помочь [актуализировать эту страницу](../support.md#participate), чтобы через это помочь другим пользователям с выбором и настройкой плеера под свои цели.
|
||||
Если ты имел дело с каким-то плеером, знаешь как его настроить или какие-то другие детали, я прошу тебя помочь [актуализировать эту страницу](support.md#participate), чтобы через это помочь другим пользователям с выбором и настройкой плеера под свои цели.
|
||||
|
||||
## Кроссплатформенные
|
||||
|
||||
@@ -33,17 +33,17 @@ tags: ["плееры"]
|
||||
Универсальный плеер практически для любого мультимедиа-контента.
|
||||
|
||||
??? quote "[Скриншот] Главное окно"
|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста на десктопе"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста на андроиде"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### :thumbsup: IPTVnator
|
||||
|
||||
@@ -58,12 +58,12 @@ tags: ["плееры"]
|
||||
Если использовать веб-версию, то настройки сохраняются в браузере.
|
||||
|
||||
??? quote "[Скриншот] Главное окно"
|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### IPTV Web Player
|
||||
|
||||
@@ -75,11 +75,11 @@ tags: ["плееры"]
|
||||
Подгрузка и отображение телепрограммы (используется https://cdn.epg.one/epg2.xml).
|
||||
|
||||
??? quote "[Скриншот] Главное окно"
|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста"
|
||||
!!! success "Указание протокола `https://` необязательно!"
|
||||

|
||||

|
||||
|
||||
### Kodi
|
||||
|
||||
@@ -136,11 +136,11 @@ tags: ["плееры"]
|
||||
Поддерживает плейлисты по ссылкам, сторонние телепрограммы, группировку каналов, изменение плейлистов и многое другое.
|
||||
|
||||
??? quote "[Скриншот] Главное окно"
|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -174,24 +174,24 @@ tags: ["плееры"]
|
||||
* Скачать: [play.google.com](https://play.google.com/store/apps/details?id=com.ottplay.ottplay)
|
||||
|
||||
??? quote "[Скриншот] Главный экран"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
Из настроек:
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
И дальше те же шаги 3-5 на скриншотах выше.
|
||||
|
||||
??? quote "Установка User-Agent"
|
||||
На экране добавления/редактирования плейлиста снять галочку "User-Agent по умолчанию" и ввести необходимый.
|
||||
Например, для [Wink](../faq.md#wink).
|
||||
Например, для [Wink](../aggregator/faq.md#wink).
|
||||
|
||||
#### :thumbsup: M3U
|
||||
|
||||
@@ -199,19 +199,19 @@ tags: ["плееры"]
|
||||
|
||||
Умеет показывать картинку-в-картинке, отображать группы и сортировать каналы.
|
||||
|
||||
Программу передач нужно [подключать отдельной ссылкой](../faq.md#epg), из плейлиста не тянет.
|
||||
Программу передач нужно [подключать отдельной ссылкой](../aggregator/faq.md#epg), из плейлиста не тянет.
|
||||
|
||||
??? quote "[Скриншот] Главный экран"
|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Добавление плейлиста"
|
||||
!!! warning "Указание протокола `https://` обязательно!"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
??? quote "[Скриншот] Установка User-Agent"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
#### IPTV (Александр Софронов)
|
||||
|
||||
@@ -16,7 +16,7 @@ icon: material/hand-heart-outline
|
||||
Там можно ставить **платные реакции** к постам и/или **дарить голоса** (бусты):
|
||||
|
||||
* канал: [@iptv_aggregator](https://t.me/iptv_aggregator) ([boost](https://t.me/iptv_aggregator?boost)) — в нём новости о проекте (общие объявления и проведённые доработки);
|
||||
* чат: [@iptv_aggregator_chat](tg/chat.md) ([boost](https://t.me/iptv_aggregator_chat?boost)) — комментарии к каналу, общение по теме проекта и IPTV.
|
||||
* чат: [@iptv_aggregator_chat](../tg/chat.md) ([boost](https://t.me/iptv_aggregator_chat?boost)) — комментарии к каналу, общение по теме проекта и IPTV.
|
||||
|
||||
## :material-wallet: Внести пожертвование
|
||||
|
||||
@@ -36,8 +36,7 @@ icon: material/hand-heart-outline
|
||||
|
||||
На пожертвования [был приобретён](https://t.me/iptv_aggregator/30) домен `m3u.su`, который сейчас используется в качестве основного адреса.
|
||||
|
||||
<a id="participate"></a>
|
||||
## :simple-git: Принять участие в разработке
|
||||
## :simple-git: Принять участие в разработке { id="participate" }
|
||||
|
||||
Весь исходный код проекта хранится в репозиториях организации: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Главная
|
||||
template: landing.html
|
||||
hide: [navigation, toc]
|
||||
hero:
|
||||
title: Агрегатор плейлистов
|
||||
subtitle: Бесплатный сервис для сбора публичных IPTV-плейлистов с автоматической проверкой доступности каналов
|
||||
buttons:
|
||||
- text: О сервисе
|
||||
url: aggregator/overview.html
|
||||
primary: true
|
||||
- text: Открыть сайт
|
||||
url: https://m3u.su
|
||||
primary: false
|
||||
---
|
||||
|
||||
# Главная
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-home:{ .lg .middle } **Агрегатор m3u.su**
|
||||
|
||||
---
|
||||
|
||||
Что это за сервис, как он работает, проверки и статусы плейлистов
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](aggregator/overview.md){ .md-button .md-button--primary }
|
||||
|
||||
- :material-console:{ .lg .middle } **iptvc**
|
||||
|
||||
---
|
||||
|
||||
CLI-утилита для проверки IPTV-плейлистов: установка, команды, конфигурация
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](iptvc/overview.md){ .md-button .md-button--primary }
|
||||
|
||||
- :material-web:{ .lg .middle } **Запуск сайта**
|
||||
|
||||
---
|
||||
|
||||
Создай собственный агрегатор плейлистов на базе iptvc
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](iptvc/site/first-steps.md){ .md-button .md-button--primary }
|
||||
|
||||
- :material-file-cog:{ .lg .middle } **Конфигурация**
|
||||
|
||||
---
|
||||
|
||||
Полное описание `config.yml`, переменных окружения и CLI-флагов
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](common/config/config.md){ .md-button .md-button--primary }
|
||||
|
||||
- :material-multimedia:{ .lg .middle } **IPTV плееры**
|
||||
|
||||
---
|
||||
|
||||
Подборка плееров для всех платформ: desktop, mobile, TV
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](common/players.md){ .md-button .md-button--primary }
|
||||
|
||||
- :material-hand-heart:{ .lg .middle } **Поддержка проекта**
|
||||
|
||||
---
|
||||
|
||||
Ghjtrn
|
||||
|
||||
[Подробнее :octicons-arrow-right-24:](common/support.md){ .md-button .md-button--primary }
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,384 @@
|
||||
---
|
||||
title: check
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `check`
|
||||
|
||||
Команда поддерживает множество аргументов для разных целей.
|
||||
|
||||
Они могут дополнять друг друга.
|
||||
|
||||
Порядок аргументов не имеет значения.
|
||||
|
||||
## `-i`, `--ini` { id=ini }
|
||||
|
||||
Указывает путь к локальному [ini-файлу](../../common/formats/playlists.md) с описанием плейлистов.
|
||||
|
||||
Можно указать только однажды.
|
||||
|
||||
Значение по умолчанию: `./playlists.ini`
|
||||
|
||||
Если файл не найден, проверка плейлистов будет доступна только по ссылкам ([`--url`](#url)) или из локальных файлов ([`--file`](#file)).
|
||||
|
||||
```shell title="Пример"
|
||||
./iptvc check -i ~/my.ini
|
||||
```
|
||||
|
||||
## `-t`, `--tags` { id=tags }
|
||||
|
||||
Указывает путь к локальному [json-файлу](../../common/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](../../common/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
|
||||
```
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
tags: ["iptvc"]
|
||||
title: help
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `help`
|
||||
@@ -27,11 +28,15 @@ Available Commands:
|
||||
check Check playlists
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
help Help about any command
|
||||
serve Start web interface
|
||||
version Show version
|
||||
|
||||
Flags:
|
||||
-h, --help help for iptvc
|
||||
-v, --verbose enable additional output
|
||||
--config string path to config file (default "config.yml")
|
||||
--debug enable debug mode (overrides config.yml)
|
||||
-h, --help help for iptvc
|
||||
--log-level string log level: debug, info, warn, error (overrides config.yml)
|
||||
-v, --verbose enable additional output
|
||||
|
||||
Use "iptvc [command] --help" for more information about a command.
|
||||
```
|
||||
@@ -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,377 @@
|
||||
---
|
||||
title: serve
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `serve`
|
||||
|
||||
Запускает встроенный веб-сервер для просмотра плейлистов и результатов их проверки в браузере.
|
||||
|
||||
```bash
|
||||
iptvc serve [flags]
|
||||
```
|
||||
|
||||
## Веб-сервер
|
||||
|
||||
### `-p`, `--port` { id="port" }
|
||||
|
||||
Порт для веб-сервера.
|
||||
|
||||
Переопределяет `server.port` из `config.yml` и переменную `WEB_PORT`.
|
||||
|
||||
Если не указан, используется значение из `config.yml` (по умолчанию `8080`).
|
||||
|
||||
```bash
|
||||
iptvc serve -p 3000
|
||||
```
|
||||
|
||||
### `--host` { id="host" }
|
||||
|
||||
Хост для привязки веб-сервера.
|
||||
|
||||
Переопределяет `server.host` из `config.yml` и переменную `WEB_HOST`.
|
||||
|
||||
Если не указан, используется значение из `config.yml` (по умолчанию — все интерфейсы).
|
||||
|
||||
```bash
|
||||
iptvc serve --host 127.0.0.1
|
||||
```
|
||||
|
||||
## Фоновая проверка
|
||||
|
||||
### `--check` { id="check" }
|
||||
|
||||
Включает фоновую проверку плейлистов. По умолчанию выключена.
|
||||
|
||||
Без этого флага веб-сервер работает standalone — отображает данные из кеша (если включён) или статус `unknown` для всех плейлистов.
|
||||
|
||||
```bash
|
||||
iptvc serve --check
|
||||
```
|
||||
|
||||
При `--check` доступны следующие флаги:
|
||||
|
||||
### `-i`, `--ini` { id="ini" }
|
||||
|
||||
Путь к локальному [ini-файлу](../../common/formats/playlists.md) с описанием плейлистов.
|
||||
|
||||
Значение по умолчанию: `./playlists.ini`
|
||||
|
||||
```bash
|
||||
iptvc serve --check -i ~/my.ini
|
||||
```
|
||||
|
||||
### `-t`, `--tags` { id="tags" }
|
||||
|
||||
Путь к [json-файлу](../../common/formats/channels.md) с описанием тегов каналов.
|
||||
|
||||
Значение по умолчанию: `./channels.json`
|
||||
|
||||
```bash
|
||||
iptvc serve --check -t ~/tags.json
|
||||
```
|
||||
|
||||
### `--every` { id="every" }
|
||||
|
||||
Интервал между циклами фоновой проверки в секундах.
|
||||
|
||||
Значение по умолчанию: `60`
|
||||
|
||||
```bash
|
||||
iptvc serve --check --every 120
|
||||
```
|
||||
|
||||
### `--repeat` { id="repeat" }
|
||||
|
||||
Количество циклов фоновой проверки.
|
||||
|
||||
Значение по умолчанию: `0` (бесконечно)
|
||||
|
||||
```bash
|
||||
# проверить один раз и остановить фоновую проверку
|
||||
iptvc serve --check --repeat 1
|
||||
```
|
||||
|
||||
### `-r`, `--random` { id="random" }
|
||||
|
||||
Максимальное количество случайных плейлистов из ini-файла для проверки.
|
||||
|
||||
```bash
|
||||
iptvc serve --check -r 10
|
||||
```
|
||||
|
||||
## Глобальные флаги
|
||||
|
||||
### `--config` { id="config" }
|
||||
|
||||
Путь к файлу конфигурации `config.yml`.
|
||||
|
||||
Значение по умолчанию: `config.yml`
|
||||
|
||||
```bash
|
||||
iptvc serve --config /etc/iptvc/config.yml
|
||||
```
|
||||
|
||||
### `--debug` { id="debug" }
|
||||
|
||||
Включает режим отладки. Переопределяет `app.debug` из `config.yml` и переменную `APP_DEBUG`.
|
||||
|
||||
```bash
|
||||
iptvc serve --debug
|
||||
```
|
||||
|
||||
### `--log-level` { id="log-level" }
|
||||
|
||||
Устанавливает уровень логирования. Переопределяет `app.log_level` из `config.yml`.
|
||||
|
||||
Доступные значения: `debug`, `info`, `warn`, `error`.
|
||||
|
||||
```bash
|
||||
iptvc serve --log-level debug
|
||||
```
|
||||
|
||||
### `-v`, `--verbose` { id="verbose" }
|
||||
|
||||
Включает подробное логирование.
|
||||
|
||||
## Флаги проверки плейлистов
|
||||
|
||||
Эти флаги переопределяют параметры секции `check.playlists` из `config.yml`. Доступны для команд `check` и `serve`. Имеют смысл только при включённой фоновой проверке (`--check` или `check.start-on-serve: true`).
|
||||
|
||||
### `--playlists-timeout` { id="playlists-timeout" }
|
||||
|
||||
Таймаут HTTP-запроса плейлиста в миллисекундах.
|
||||
|
||||
Переопределяет `check.playlists.timeout` (по умолчанию `10000`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-timeout 5000
|
||||
```
|
||||
|
||||
### `--playlists-all-cooldown` { id="playlists-all-cooldown" }
|
||||
|
||||
Задержка в миллисекундах после проверки всех плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.all-cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-all-cooldown 10000
|
||||
```
|
||||
|
||||
### `--playlists-one-cooldown` { id="playlists-one-cooldown" }
|
||||
|
||||
Задержка в миллисекундах после проверки каждого плейлиста.
|
||||
|
||||
Переопределяет `check.playlists.one-cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-one-cooldown 2000
|
||||
```
|
||||
|
||||
### `--playlists-max-routines` { id="playlists-max-routines" }
|
||||
|
||||
Максимум одновременно проверяемых плейлистов.
|
||||
|
||||
Переопределяет `check.playlists.max-routines` (по умолчанию `5`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-max-routines 10
|
||||
```
|
||||
|
||||
### `--playlists-per-routine` { id="playlists-per-routine" }
|
||||
|
||||
Количество плейлистов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.playlists.per-routine` (по умолчанию `1`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --playlists-per-routine 3
|
||||
```
|
||||
|
||||
### `--playlists-user-agent` { id="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`. Имеют смысл только при включённой фоновой проверке.
|
||||
|
||||
### `--channels-timeout` { id="channels-timeout" }
|
||||
|
||||
Таймаут HTTP-запроса канала в миллисекундах.
|
||||
|
||||
Переопределяет `check.channels.timeout` (по умолчанию `10000`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-timeout 8000
|
||||
```
|
||||
|
||||
### `--channels-byte-range` { id="channels-byte-range" }
|
||||
|
||||
Объём данных в байтах для загрузки от сервера при проверке канала.
|
||||
|
||||
Переопределяет `check.channels.byte-range` (по умолчанию `512`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-byte-range 1024
|
||||
```
|
||||
|
||||
### `--channels-cooldown` { id="channels-cooldown" }
|
||||
|
||||
Задержка в миллисекундах после проверки каждого канала.
|
||||
|
||||
Переопределяет `check.channels.cooldown` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-cooldown 100
|
||||
```
|
||||
|
||||
### `--channels-max-routines` { id="channels-max-routines" }
|
||||
|
||||
Максимум одновременно проверяемых каналов.
|
||||
|
||||
Переопределяет `check.channels.max-routines` (по умолчанию `50`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-max-routines 100
|
||||
```
|
||||
|
||||
### `--channels-per-routine` { id="channels-per-routine" }
|
||||
|
||||
Количество каналов на одну процедуру проверки.
|
||||
|
||||
Переопределяет `check.channels.per-routine` (по умолчанию `10`).
|
||||
|
||||
```bash
|
||||
iptvc serve --check --channels-per-routine 20
|
||||
```
|
||||
|
||||
### `--channels-user-agent` { id="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`.
|
||||
|
||||
### `--cache-enabled` { id="cache-enabled" }
|
||||
|
||||
Включает кеширование результатов в KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.enabled` (по умолчанию `false`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled
|
||||
```
|
||||
|
||||
### `--cache-host` { id="cache-host" }
|
||||
|
||||
Хост KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.host` (по умолчанию `localhost`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-host 192.168.1.10
|
||||
```
|
||||
|
||||
### `--cache-port` { id="cache-port" }
|
||||
|
||||
Порт KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.port` (по умолчанию `6379`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-port 6380
|
||||
```
|
||||
|
||||
### `--cache-username` { id="cache-username" }
|
||||
|
||||
Логин для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.username`.
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-username myuser
|
||||
```
|
||||
|
||||
### `--cache-password` { id="cache-password" }
|
||||
|
||||
Пароль для подключения к KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.password`.
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-password secret
|
||||
```
|
||||
|
||||
### `--cache-db` { id="cache-db" }
|
||||
|
||||
Номер базы данных KeyDB/Redis.
|
||||
|
||||
Переопределяет `cache.db` (по умолчанию `0`).
|
||||
|
||||
```bash
|
||||
iptvc serve --cache-enabled --cache-db 2
|
||||
```
|
||||
|
||||
### `--cache-ttl` { id="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,20 @@
|
||||
---
|
||||
title: version
|
||||
tags: [iptvc]
|
||||
---
|
||||
|
||||
# Команда `version`
|
||||
|
||||
Выводит версию программы:
|
||||
|
||||
```bash
|
||||
./iptvc version
|
||||
```
|
||||
|
||||
Пример результата:
|
||||
|
||||
```
|
||||
iptvc v1.1.3
|
||||
```
|
||||
|
||||
Версия также доступна через [API](serve.md) — endpoint `GET /api/version`.
|
||||
@@ -0,0 +1,223 @@
|
||||
---
|
||||
# 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-шаблоны
|
||||
│ ├── base.html
|
||||
│ ├── list.html
|
||||
│ ├── details.html
|
||||
│ └── notfound.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](../../common/config/config.md).
|
||||
|
||||
Приоритет: Defaults < `config.yml` < Env < CLI-флаги.
|
||||
|
||||
CLI-флаги переопределяют конфигурацию только если переданы явно (`cmd.Flags().Changed()`).
|
||||
Для этого в Cobra используются zero-value defaults (0, "", false), чтобы отличить «не передан» от «передан со значением по умолчанию».
|
||||
|
||||
## Шаблоны
|
||||
|
||||
HTML-шаблоны встроены через `//go:embed`:
|
||||
|
||||
- `base.html` — общий каркас (header, footer);
|
||||
- `list.html` — список плейлистов с пагинацией;
|
||||
- `details.html` — детали плейлиста и список каналов;
|
||||
- `notfound.html` — страница 404.
|
||||
|
||||
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,59 @@
|
||||
---
|
||||
title: Компиляция
|
||||
icon: material/cog
|
||||
tags: ["iptvc", "сборка"]
|
||||
---
|
||||
|
||||
# Компиляция из исходного кода
|
||||
|
||||
Для компиляции потребуется [Go](https://go.dev/dl/) 1.23.6 и выше.
|
||||
|
||||
```bash
|
||||
git clone https://git.axenov.dev/IPTV/iptvc.git
|
||||
cd iptvc
|
||||
make linux
|
||||
# или make help для получения справки по рецептам
|
||||
```
|
||||
|
||||
## Доступные рецепты Makefile
|
||||
|
||||
| Команда | Назначение |
|
||||
| --- | --- |
|
||||
| `make linux` | Сборка под Linux (amd64 по умолчанию) |
|
||||
| `make win` | Сборка под Windows |
|
||||
| `make darwin` | Сборка под macOS |
|
||||
| `make release` | Сборка под все платформы (linux/windows/darwin × amd64/arm64) |
|
||||
| `make clean` | Удаление скомпилированных бинарников |
|
||||
| `make help` | Вывод списка доступных рецептов |
|
||||
|
||||
## Управление архитектурой
|
||||
|
||||
Архитектура целевой платформы задаётся переменной `GOARCH`:
|
||||
|
||||
```bash
|
||||
make darwin GOARCH=arm64 # macOS на Apple Silicon
|
||||
make linux GOARCH=arm64 # Linux ARM (Raspberry Pi и т.п.)
|
||||
```
|
||||
|
||||
## Результат
|
||||
|
||||
Скомпилированные бинарники и ZIP-архивы помещаются в директорию `bin/`:
|
||||
|
||||
```
|
||||
bin/
|
||||
├── linux_amd64/iptvc # или linux_arm64/
|
||||
├── linux_amd64.zip
|
||||
├── windows_amd64/iptvc.exe # или windows_arm64/
|
||||
├── windows_amd64.zip
|
||||
├── darwin_amd64/iptvc # или darwin_arm64/
|
||||
└── darwin_amd64.zip
|
||||
```
|
||||
|
||||
## Сборка без Make
|
||||
|
||||
Можно скомпилировать напрямую через `go build`:
|
||||
|
||||
```bash
|
||||
go build -o iptvc .
|
||||
go build -trimpath -ldflags="-s -w" -o iptvc .
|
||||
```
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Docker-образ
|
||||
icon: simple/docker
|
||||
tags: ["iptvc", "docker"]
|
||||
---
|
||||
|
||||
# Построение Docker-образа
|
||||
|
||||
## Сборка
|
||||
|
||||
Образ собирается из [Dockerfile](https://git.axenov.dev/IPTV/iptvc/src/branch/master/Dockerfile) — multi-stage сборка на базе `golang:1.25-alpine` с финальным образом `alpine:3.22`.
|
||||
|
||||
```bash
|
||||
docker build -t iptvc ./iptvc
|
||||
```
|
||||
|
||||
Можно передать версию через build-arg:
|
||||
|
||||
```bash
|
||||
docker build --build-arg IPTVC_VERSION=1.1.3 -t iptvc:v1.1.3 ./iptvc
|
||||
```
|
||||
|
||||
Целевая платформа и архитектура задаются через `GOOS` и `GOARCH`:
|
||||
|
||||
```bash
|
||||
docker build --build-arg GOOS=linux --build-arg GOARCH=arm64 -t iptvc:linux-arm64 ./iptvc
|
||||
```
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
# Проверка плейлистов
|
||||
docker run --rm \
|
||||
-v ./playlists.ini:/app/playlists.ini \
|
||||
-v ./channels.json:/app/channels.json \
|
||||
iptvc check -i playlists.ini --repeat 0 --every 60
|
||||
|
||||
# Веб-сервер с фоновой проверкой
|
||||
docker run --rm -p 8080:8080 \
|
||||
-v ./playlists.ini:/app/playlists.ini \
|
||||
-v ./channels.json:/app/channels.json \
|
||||
iptvc serve -i playlists.ini -p 8080 --check
|
||||
```
|
||||
|
||||
## Использование в compose
|
||||
|
||||
В `compose.yml` сервиса `checker` образ собирается автоматически:
|
||||
|
||||
```yaml
|
||||
checker:
|
||||
image: git.axenov.dev/iptv/iptvc:latest
|
||||
build:
|
||||
context: ./iptvc
|
||||
dockerfile: Dockerfile
|
||||
command: ["check", "--repeat", "0", "--every", "${CHECKER_WAIT:-60}"]
|
||||
```
|
||||
|
||||
Подробнее о полном окружении — в разделе [Развёртывание](../site/deploy.md).
|
||||
@@ -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 "Пустое содержимое"
|
||||
|
||||
|
||||
---
|
||||
@@ -6,7 +6,7 @@ icon: material/book-cog-outline
|
||||
|
||||
## Стилистика и правила оформления
|
||||
|
||||
Все исходники хранятся в директории `src/` в формате **Markdown** (формат файлов `.md`).
|
||||
Все исходники хранятся в директории `content/` в формате **Markdown** (формат файлов `.md`).
|
||||
|
||||
Структура проекта и его конфигурация описываются в файле `mkdocs.yml` в корне репозитория.
|
||||
|
||||
@@ -24,7 +24,7 @@ icon: material/book-cog-outline
|
||||
|
||||
## Добавление изображений
|
||||
|
||||
**Все изображения хранятся только в директории `src/assets/img/` и вложенных в неё.**
|
||||
**Все изображения хранятся в директории `_assets/` рядом с документом.**
|
||||
|
||||
Общая суть такова:
|
||||
|
||||
@@ -49,8 +49,8 @@ icon: material/book-cog-outline
|
||||
Совершенно любой текст, lorem ipsum dolor sit amet.
|
||||
|
||||
??? quote "В этом спойлере несколько больших картинок"
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
@@ -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,71 @@
|
||||
---
|
||||
icon: material/application-brackets-outline
|
||||
tags: ["iptvc", "разработка"]
|
||||
---
|
||||
|
||||
# :material-application-brackets-outline: Среда разработки
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
Для локальной разработки `iptvc` достаточно установить [Go 1.23.6+][1] и клонировать репозиторий:
|
||||
|
||||
```bash
|
||||
git clone https://git.axenov.dev/IPTV/iptvc.git
|
||||
cd iptvc
|
||||
go run . serve -i playlists.ini -p 8080 --check
|
||||
```
|
||||
|
||||
Веб-интерфейс будет доступен по адресу <http://localhost:8080>.
|
||||
|
||||
## Требования
|
||||
|
||||
| ПО | Версия | Назначение |
|
||||
| ----------- | --------------------- | ------------------------------------- |
|
||||
| [Go][1] | 1.23.6+ | Компиляция и запуск |
|
||||
| [Make][2] | любая | Сборка через `Makefile` (опционально) |
|
||||
| [Docker][3] | с `docker compose` v2 | Полное окружение (опционально) |
|
||||
|
||||
[1]: https://go.dev/dl/
|
||||
[2]: https://www.gnu.org/software/make
|
||||
[3]: https://docs.docker.com/engine/install
|
||||
|
||||
|
||||
## Команды для разработки
|
||||
|
||||
```bash
|
||||
# Запуск веб-сервера с фоновой проверкой
|
||||
go run . serve -i playlists.ini -p 8080 --check
|
||||
|
||||
# Запуск проверки без веб-сервера
|
||||
go run . check -i playlists.ini --repeat 1
|
||||
|
||||
# Сборка бинарника
|
||||
go build -o iptvc .
|
||||
|
||||
# Проверка кода
|
||||
go vet ./...
|
||||
|
||||
# Сборка под все платформы
|
||||
make release
|
||||
```
|
||||
|
||||
## Файлы конфигурации
|
||||
|
||||
Для работы `iptvc` нужны два файла рядом с бинарником:
|
||||
|
||||
- `playlists.ini` — список плейлистов. Формат описан в [справочнике форматов](../../common/formats/playlists.md).
|
||||
- `channels.json` — правила тегов каналов. Формат описан в [справочнике форматов](../../common/formats/channels.md).
|
||||
- `config.yml` — конфигурация программы. Описание — в [разделе config.yml](../../common/config/config.md).
|
||||
|
||||
## Полное Docker-окружение
|
||||
|
||||
Полная инфраструктура проекта (nginx, KeyDB, checker, docs) развёртывается через Docker.
|
||||
|
||||
Подробнее — в разделе [Развёртывание](../site/deploy.md).
|
||||
|
||||
## Дополнительные материалы
|
||||
|
||||
- [Компиляция из исходного кода](compile.md)
|
||||
- [Построение Docker-образа](docker.md)
|
||||
- [Архитектура iptvc](arch.md)
|
||||
- [Развёртывание и доставка обновлений](../site/deploy.md)
|
||||
@@ -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.1.3 \ #(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/first-steps.md "Перейти к разделу"
|
||||
[cli]: commands/index.md "Перейти к разделу"
|
||||
[cfg]: ../common/config/config.md "Перейти к разделу"
|
||||
|
||||
<!--
|
||||
## :material-cog-sync-outline: Как работает `iptvc`
|
||||
|
||||
Принцип её работы очень простой:
|
||||
|
||||
1. Получить плейлист по ссылке.
|
||||
2. Полученный плейлист распарсить:
|
||||
обрабатывается полученный текст в формате [m3u](../common/formats/m3u.md), из него вычленется информация о каналах и их группировке.
|
||||
3. Каждый найденный канал проверить:
|
||||
получить информацию по ссылке и принять решение — работает ли канал (технически) или нет.
|
||||
4. Если необходимо, каждому каналу [присвоить теги](../common/formats/channels.md#доступные-теги) согласно [правилам](../common/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`](../common/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](../common/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`).
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
@@ -5,10 +5,10 @@ tags: ["плееры", "плейлисты"]
|
||||
|
||||
# :material-television-play: Как подключить плейлист
|
||||
|
||||
1. Найти какой-нибудь [плеер](./players.md)
|
||||
1. Найти какой-нибудь [плеер](../../common/players.md)
|
||||
2. Узнать как в него добавить плейлист по ссылке
|
||||
3. Найти желаемый плелист из [списка](./list.md)
|
||||
4. Найти на странице ["Ссылку для ТВ"](details.md#shortlink) и ввести (скопировать) её в поле ввода адреса в плеере
|
||||
|
||||
Для некоторых [плееров](./players.md) уже есть информация как добавить плейлист.
|
||||
Для некоторых [плееров](../../common/players.md) уже есть информация как добавить плейлист.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
icon: material/upload-network
|
||||
tags: ["iptvc", "docker", "deploy"]
|
||||
---
|
||||
|
||||
# :material-upload-network: Развёртывание и доставка обновлений
|
||||
|
||||
В этом разделе описано, как развернуть полную инфраструктуру проекта m3u.su на собственном сервере: веб-сервер, фоновую проверку плейлистов, кеш и документацию.
|
||||
|
||||
## Требования
|
||||
|
||||
- [Docker](https://docs.docker.com/engine/install/) с плагином `docker compose` (v2)
|
||||
- Доступ к репозиториям `git.axenov.dev/IPTV`
|
||||
|
||||
## Структура окружения
|
||||
|
||||
Полное Docker-окружение описано в `compose.yml` и состоит из пяти сервисов:
|
||||
|
||||
| Сервис | Образ | Назначение |
|
||||
| --------- | ---------------------------- | -------------------------------------- |
|
||||
| `nginx` | `nginx:latest` | Reverse-proxy, порт 3000→80 |
|
||||
| `keydb` | `eqalpha/keydb:latest` | Кеш (форк Redis), порт 6379 |
|
||||
| `web` | PHP-FPM (сборка из `web/`) | Legacy веб-слой |
|
||||
| `checker` | `iptvc` (сборка из `iptvc/`) | Фоновая проверка плейлистов |
|
||||
| `docs` | MkDocs (сборка из `docs/`) | Статическая документация, порт 3001→80 |
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
Перед запуском скопируйте `.env.example` в `.env` и при необходимости отредактируйте:
|
||||
|
||||
| Переменная | По умолчанию | Назначение |
|
||||
| ----------------- | -------------------- | ----------------------------------------------- |
|
||||
| `IPTV_ENV` | `dev` | Окружение (`dev`/`prod`), влияет на конфиги PHP |
|
||||
| `KEYDB_UID` | `1000` | ID пользователя KeyDB |
|
||||
| `KEYDB_GID` | `1000` | ID группы KeyDB |
|
||||
| `KEYDB_PORT` | `6379` | Порт KeyDB на хосте |
|
||||
| `KEYDB_USERNAME` | (пусто) | Логин KeyDB |
|
||||
| `KEYDB_PASSWORD` | (пусто) | Пароль KeyDB |
|
||||
| `CHECKER_DB` | `0` | Номер БД KeyDB для кеша |
|
||||
| `CHECKER_TTL` | `1800` | TTL кеша в секундах |
|
||||
| `CHECKER_WAIT` | `60` | Секунд между запусками `iptvc check` |
|
||||
| `CHECKER_INIFILE` | `/app/playlists.ini` | Путь к `playlists.ini` в контейнере |
|
||||
| `CHECKER_TAGFILE` | `/app/channels.json` | Путь к `channels.json` в контейнере |
|
||||
|
||||
## Управление через скрипт `iptv`
|
||||
|
||||
В корне репозитория находится bash-скрипт `iptv` для управления окружением:
|
||||
|
||||
```bash
|
||||
./iptv init # клонировать подпроекты, собрать и запустить
|
||||
./iptv up # построить и запустить контейнеры
|
||||
./iptv down # остановить и удалить контейнеры
|
||||
./iptv rebuild # down + up (с пересборкой образов)
|
||||
./iptv restart # stop + start
|
||||
./iptv stop # остановить контейнеры
|
||||
./iptv start # запустить контейнеры
|
||||
./iptv purge # удалить контейнеры и образы
|
||||
./iptv logs <сервис> # логи сервиса
|
||||
./iptv stats --no-stream # потребление ресурсов
|
||||
./iptv exec <сервис> <команда> # команда в контейнере
|
||||
./iptv exec --root <сервис> <команда> # от имени root
|
||||
```
|
||||
|
||||
!!! warning "docker compose v2"
|
||||
Скрипт использует `docker compose` (v2). `docker-compose` (v1) не поддерживается.
|
||||
|
||||
## Ручное управление
|
||||
|
||||
Без скрипта `iptv` можно управлять окружением напрямую:
|
||||
|
||||
```bash
|
||||
# Запуск всех сервисов
|
||||
docker compose up -d --build
|
||||
|
||||
# Остановка
|
||||
docker compose down
|
||||
|
||||
// Логи конкретного сервиса
|
||||
docker compose logs -f checker
|
||||
|
||||
// Перезапуск одного сервиса
|
||||
docker compose restart checker
|
||||
```
|
||||
|
||||
## Сервис `checker`
|
||||
|
||||
Контейнер `checker` запускает `iptvc` с командой:
|
||||
|
||||
```bash
|
||||
check --repeat 0 --every ${CHECKER_WAIT:-60}
|
||||
```
|
||||
|
||||
Это означает бесконечную (`--repeat 0`) фоновую проверку всех плейлистов из `playlists.ini` каждые 60 секунд (настраивается через `CHECKER_WAIT`).
|
||||
|
||||
Контейнер монтирует:
|
||||
|
||||
- `playlists/playlists.ini` → `/app/playlists.ini`
|
||||
- `playlists/channels.json` → `/app/channels.json`
|
||||
- `iptvc/config.yml` → `/app/config.yml` (только чтение)
|
||||
|
||||
Переменные окружения для кеша передаются автоматически из `.env`.
|
||||
|
||||
## Обновление
|
||||
|
||||
Чтобы обновить образы и пересобрать контейнеры:
|
||||
|
||||
```bash
|
||||
./iptv rebuild
|
||||
```
|
||||
|
||||
Или вручную:
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Для обновления только `iptvc`:
|
||||
|
||||
```bash
|
||||
docker compose build checker
|
||||
docker compose up -d checker
|
||||
```
|
||||
@@ -7,7 +7,7 @@ tags: ["сайт", "статусы", "каналы"]
|
||||
|
||||
Страница содержит подробности об одном конкретном плейлисте.
|
||||
|
||||
В её заголовке указано [название плейлиста](../formats/playlists.md#name).
|
||||
В её заголовке указано [название плейлиста](../../common/formats/playlists.md#name).
|
||||
|
||||
Ниже страница разделена на две части: слева две вкладки с информацией и список каналов справа.
|
||||
|
||||
@@ -15,28 +15,28 @@ tags: ["сайт", "статусы", "каналы"]
|
||||
|
||||
## Вкладка "Основная информация"
|
||||
|
||||

|
||||

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

|
||||

|
||||
|
||||
!!! info
|
||||
Если в тексте ошибки фигурирует слово `Timeout` и плейлист <span class="badge offline">offline</span> — это ерунда.
|
||||
@@ -49,7 +49,7 @@ tags: ["сайт", "статусы", "каналы"]
|
||||
|
||||
## Вкладка "Исходный текст"
|
||||
|
||||

|
||||

|
||||
|
||||
Здесь выводится плейлист как он есть.
|
||||
Над этим текстом — две кнопки:
|
||||
@@ -61,7 +61,7 @@ tags: ["сайт", "статусы", "каналы"]
|
||||
|
||||
В заголовке пишется их общее количество.
|
||||
|
||||

|
||||

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

|
||||

|
||||
|
||||
<a id="shortlink"></a>
|
||||
## Ссылка для ТВ
|
||||
## Ссылка для ТВ { id="shortlink" }
|
||||
|
||||
Она может быть задана в нескольких форматах.
|
||||
Поясню базовые принципы формирования адреса:
|
||||
@@ -119,13 +118,13 @@ m3u.su/ru.m3u
|
||||
m3u.su/ru
|
||||
```
|
||||
|
||||
!!! info ""
|
||||
Запоминать их не надо.
|
||||
Главное помнить как они формируются.
|
||||
!!! info "Адрес может быть любым"
|
||||
Смотря как будет развёрнут сайт, ты можешь заходить на localhost, либо по прямому IP-адресу или доменному имения.
|
||||
См. раздел [**Развёртывание**](deploy.md) для подробностей.
|
||||
|
||||
По идее, можешь использовать любую сылку из подобных, т. к. технически они отработают одинаково.
|
||||
По идее, можешь использовать любую ссылку из подобных, т. к. технически они отработают одинаково.
|
||||
|
||||
А вот твой [плеер](players.md) может не принять какую-то из них.
|
||||
А вот твой [плеер](../../common/players.md) может не принять какую-то из них.
|
||||
Так что, если не подойдёт один формат, используй другой — добавь префикс или суффикс.
|
||||
|
||||
Префикс плееру требуется чаще всего, потому что он при добавлении плейлиста проверяет — а ссылку ли мне вообще предоставил пользователь?
|
||||
@@ -0,0 +1,415 @@
|
||||
---
|
||||
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`](../../common/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`](../../common/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`](../../common/config/config.md):
|
||||
|
||||
```yaml title="config.yml"
|
||||
check:
|
||||
start-on-serve: true
|
||||
```
|
||||
|
||||
Тогда обычный `./iptvc serve` автоматически запустит фоновую проверку.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4. Настраиваем внешний вид сайта
|
||||
|
||||
Сайт можно настроить под себя: заголовок, иконку, навигацию в шапке и ссылки в подвале.
|
||||
Всё это — в секции [`site`](../../common/config/config.md) файла `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`](../../common/formats/channels.md).
|
||||
|
||||
```json title="channels.json"
|
||||
[
|
||||
{
|
||||
"tvg-id": "^ru-",
|
||||
"tags": ["russian"]
|
||||
},
|
||||
{
|
||||
"title": "спорт",
|
||||
"tags": ["sport"]
|
||||
},
|
||||
{
|
||||
"title": "кино|фильм",
|
||||
"tags": ["film"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Путь к файлу указывается в [`config.yml`](../../common/config/config.md) → `app.tags` или через флаг [`-t`](../commands/serve.md#tags):
|
||||
|
||||
```bash
|
||||
./iptvc serve --check -t /path/to/channels.json
|
||||
```
|
||||
|
||||
Полный список доступных тегов — в [справочнике по channels.json](../../common/formats/channels.md#доступные-теги).
|
||||
|
||||
---
|
||||
|
||||
## Шаг 6. Подключаем кеш (KeyDB/Redis)
|
||||
|
||||
По умолчанию результаты проверки хранятся только в оперативной памяти.
|
||||
Если программу перезапустить — все результаты пропадут, и плейлисты снова станут `unknown` до следующей проверки.
|
||||
|
||||
Кеш решает эту проблему: результаты сохраняются в KeyDB (или Redis) и переживают перезапуск.
|
||||
Включается одной строкой в [`config.yml`](../../common/config/config.md):
|
||||
|
||||
```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`](../../common/config/config.md) файла `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
|
||||
```
|
||||
|
||||
Все эти параметры можно также задавать через [переменные окружения](../../common/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`](../../common/config/config.md), [переменным окружения](../../common/config/env.md) и [команде `serve`](../commands/serve.md).
|
||||
@@ -5,10 +5,10 @@ tags: ["плейлисты", "каналы", "теги", "iptvc", "плееры"
|
||||
|
||||
# :material-cogs: Как работает сервис
|
||||
|
||||
1. В специальном файле [playlists.ini](../formats/playlists.md) описываются плейлисты, которые кем-то опубликованы в интернете.
|
||||
1. В специальном файле [playlists.ini](../../common/formats/playlists.md) описываются плейлисты, которые кем-то опубликованы в интернете.
|
||||
Каждому плейлисту присваивается свой уникальный **короткий код**.
|
||||
2. В специальном файле [channels.json](../formats/channels.md) описываются **ключевые слова** (метки, теги), которые характеризуют каналы.
|
||||
3. В фоновом режиме [работает ПО](../iptvc/index.md), которое периодически [проверяет все плейлисты](checks.md) из п. 1 и **присваивает теги** каналам из п. 2.
|
||||
2. В специальном файле [channels.json](../../common/formats/channels.md) описываются **ключевые слова** (метки, теги), которые характеризуют каналы.
|
||||
3. В фоновом режиме [работает ПО](../overview.md), которое периодически [проверяет все плейлисты](../../aggregator/checks.md) из п. 1 и **присваивает теги** каналам из п. 2.
|
||||
4. На главной странице сайта выводится [весь список плейлистов](list.md), которые описаны в п. 1: с тегами, описаниями и короткими кодами.
|
||||
5. Каждому плейлисту на сайте посвящена [своя страничка](details.md), где отображаются результаты его проверки, проверки его каналов (с присвоенными тегами) и пр.
|
||||
6. Когда пользователь [обращается к плейлисту](connect.md) по короткому коду (например, `https://m3u.su/xyz`), то происходит **переадресация** на исходный плейлист.
|
||||
@@ -7,30 +7,30 @@ tags: ["сайт", "плейлисты"]
|
||||
|
||||
Это главная страница сайта.
|
||||
|
||||

|
||||

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

|
||||

|
||||
@@ -5,7 +5,7 @@ icon: material/wallet-outline
|
||||
# :material-wallet-outline: Правообладателям
|
||||
|
||||
Данные, представленные на сайте https://m3u.su, получены автоматически из открыто доступных в интернете IPTV-плейлистов, опубликованных третьими лицами.
|
||||
При наличии технической возможности, источник плейлиста может быть указан на вкладке [«Основные данные»](common/details.md).
|
||||
При наличии технической возможности, источник плейлиста может быть указан на вкладке [«Основные данные»](../iptvc/site/details.md).
|
||||
|
||||
Сервис https://m3u.su не размещает и не транслирует медиаконтент, не создаёт, не призывает использовать и распространять плейлисты третьих лиц, а также не оказывает услуг по ретрансляции телепрограмм.
|
||||
|
||||
@@ -27,12 +27,11 @@ tags: ["telegram"]
|
||||
К людям надо относиться по-человечески.
|
||||
Твой юмор могут не понять, а пассивную агрессию и дерзость не любит никто.
|
||||
|
||||
<a id="checklist"></a>
|
||||
## Я только спросить!
|
||||
## Я только спросить! { id="checklist" }
|
||||
|
||||
Держи чеклист:
|
||||
|
||||
1. **Найди ответ в [FAQ](../faq.md)**
|
||||
1. **Найди ответ в [FAQ](../aggregator/faq.md)**
|
||||
2. Если не нашёл ответ — прочти остальное
|
||||
3. Если не нашёл ответ и это проблема:
|
||||
* опиши всю ситуацию — сухо и по существу, в чём проблема, чего хочешь и ожидаешь;
|
||||
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from html import escape
|
||||
|
||||
from markdown.extensions import Extension
|
||||
from markdown.preprocessors import Preprocessor
|
||||
|
||||
SHORTCODE_RE = re.compile(r"<!--\s*md:(version|default|flag)\s*(.*?)\s*-->", re.I)
|
||||
|
||||
class BadgePreprocessor(Preprocessor):
|
||||
def run(self, lines: list[str]) -> list[str]:
|
||||
return [SHORTCODE_RE.sub(self._replace, line) for line in lines]
|
||||
|
||||
def _replace(self, match: re.Match[str]) -> str:
|
||||
kind, args = match.groups()
|
||||
args = args.strip()
|
||||
|
||||
if kind == "version":
|
||||
return _badge(":material-tag-outline:", escape(args))
|
||||
|
||||
if kind == "default":
|
||||
value = escape(args or "none")
|
||||
return _badge(":material-water:", f"<code>{value}</code>")
|
||||
|
||||
if kind == "flag" and args == "experimental":
|
||||
return _badge(":material-test-tube:")
|
||||
|
||||
return match.group(0)
|
||||
|
||||
|
||||
# Формирует HTML-разметку бейджа. Иконки остаются Zensical-шорткодами
|
||||
# и рендерятся штатным `pymdownx.emoji` на следующем этапе обработки Markdown.
|
||||
def _badge(icon: str, text: str = "") -> str:
|
||||
return "".join([
|
||||
'<span class="mdx-badge">',
|
||||
f'<span class="mdx-badge__icon">{icon}</span>',
|
||||
*([f'<span class="mdx-badge__text">{text}</span>'] if text else []),
|
||||
'</span>',
|
||||
])
|
||||
|
||||
|
||||
class InlineBadgeExtension(Extension):
|
||||
def extendMarkdown(self, md):
|
||||
md.preprocessors.register(BadgePreprocessor(md), "inline_badges", 175)
|
||||
|
||||
|
||||
def makeExtension(**kwargs):
|
||||
return InlineBadgeExtension(**kwargs)
|
||||
@@ -1,144 +0,0 @@
|
||||
site_name: Документация m3u.su
|
||||
site_description: Описание сервиса m3u.su и его компонентов
|
||||
site_author: Антон Аксенов
|
||||
copyright: Антон Аксенов © 2025 MIT License
|
||||
|
||||
repo_name: Репозиторий
|
||||
repo_url: https://git.axenov.dev/IPTV/docs
|
||||
edit_uri: src/branch/master/src/
|
||||
remote_branch: master
|
||||
|
||||
docs_dir: ./src
|
||||
use_directory_urls: false
|
||||
watch:
|
||||
- src
|
||||
extra_css:
|
||||
- assets/css/custom.css
|
||||
extra_javascript:
|
||||
- https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js
|
||||
|
||||
extra:
|
||||
homepage: /docs
|
||||
logo: assets/img/favicon/logo.png
|
||||
favicon: assets/img/favicon/logo.png
|
||||
social:
|
||||
- name: Канал @iptv_aggregator
|
||||
icon: simple/telegram
|
||||
link: https://t.me/iptv_aggregator
|
||||
- name: Чат @iptv_aggregator_chat
|
||||
icon: simple/telegram
|
||||
link: https://t.me/iptv_aggregator_chat
|
||||
- name: Бот @iptv_aggregator_bot
|
||||
icon: simple/telegram
|
||||
link: https://t.me/iptv_aggregator_bot
|
||||
|
||||
theme:
|
||||
name: 'material'
|
||||
language: ru
|
||||
features:
|
||||
- toc.follow
|
||||
- search.suggest
|
||||
- navigation.top
|
||||
- navigation.footer
|
||||
- navigation.indexes
|
||||
- content.action.edit
|
||||
icon:
|
||||
repo: simple/gitea
|
||||
edit: material/pencil
|
||||
view: material/eye
|
||||
palette:
|
||||
# Автотема
|
||||
- media: "(prefers-color-scheme)"
|
||||
toggle:
|
||||
icon: material/brightness-auto
|
||||
name: Switch to light mode
|
||||
# Тёмная тема
|
||||
- scheme: slate
|
||||
media: "(prefers-color-scheme: light)"
|
||||
accent: teal
|
||||
primary: black
|
||||
toggle:
|
||||
name: Светлая тема
|
||||
icon: material/weather-sunny
|
||||
# Светлая тема
|
||||
- scheme: default
|
||||
media: "(prefers-color-scheme: dark)"
|
||||
accent: teal
|
||||
primary: teal
|
||||
toggle:
|
||||
name: Тёмная тема
|
||||
icon: material/weather-night
|
||||
|
||||
plugins:
|
||||
- minify:
|
||||
minify_html: true
|
||||
- tags:
|
||||
tags: true
|
||||
listings: true
|
||||
- social:
|
||||
cards_layout_options:
|
||||
background_color: teal
|
||||
background_image: null
|
||||
- search:
|
||||
separator: '[\s\-\.]+'
|
||||
# indexing: 'full'
|
||||
|
||||
validation:
|
||||
omitted_files: warn
|
||||
absolute_links: warn
|
||||
unrecognized_links: warn
|
||||
anchors: warn
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.superfences
|
||||
- attr_list
|
||||
- md_in_html
|
||||
- pymdownx.emoji:
|
||||
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||
- toc:
|
||||
permalink: true
|
||||
|
||||
nav:
|
||||
- index.md
|
||||
- docs.md
|
||||
- support.md
|
||||
- legal.md
|
||||
- 'Общая информация':
|
||||
- common/index.md
|
||||
- common/how-it-works.md
|
||||
- common/selection.md
|
||||
- common/checks.md
|
||||
- common/list.md
|
||||
- common/details.md
|
||||
- common/connect.md
|
||||
- common/players.md
|
||||
- 'IPTV Checker (iptvc)':
|
||||
- iptvc/index.md
|
||||
- iptvc/install.md
|
||||
- iptvc/quickstart.md
|
||||
- iptvc/env.md
|
||||
- 'Доступные команды':
|
||||
- iptvc/commands/index.md
|
||||
- iptvc/commands/help.md
|
||||
- iptvc/commands/check.md
|
||||
- iptvc/commands/version.md
|
||||
- statuspage.md
|
||||
- 'Для разработчиков':
|
||||
- dev/index.md
|
||||
- dev/local-dev.md
|
||||
- dev/tgbot.md
|
||||
- dev/docs.md
|
||||
- dev/deploy.md
|
||||
- 'Форматы файлов':
|
||||
- formats/index.md
|
||||
- 'playlists.ini': 'formats/playlists.md'
|
||||
- 'channels.json': 'formats/channels.md'
|
||||
- '*.m3u (*.m3u8)': 'formats/m3u.md'
|
||||
- 'Telegram':
|
||||
- tg/index.md
|
||||
- 'Бот': tg/bot.md
|
||||
- 'Чат': tg/chat.md
|
||||
- 'FAQ (ЧаВо)': 'faq.md'
|
||||