wip1
@@ -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
|
/.cache/
|
||||||
/site
|
/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
|
COPY . /docs
|
||||||
RUN mkdocs build
|
RUN zensical build --clean
|
||||||
|
|
||||||
FROM nginx:alpine AS iptv-docs
|
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.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
|
COPY --from=builder /docs/site /usr/share/nginx/html
|
||||||
WORKDIR /usr/share/nginx/html
|
WORKDIR /usr/share/nginx/html
|
||||||
USER root
|
USER root
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
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:
|
live:
|
||||||
@echo "Wait until container starts and open http://localhost:3000 to see live preview"
|
@echo "*** Wait until container starts and open http://localhost:8000 to see live preview"
|
||||||
@docker run \
|
@docker stop iptv-docs-dev 2>/dev/null; \
|
||||||
--pull always \
|
docker run \
|
||||||
--rm \
|
--rm \
|
||||||
--interactive \
|
--interactive \
|
||||||
--tty \
|
--tty \
|
||||||
--publish 3000:8000 \
|
--env PYTHONPATH=/docs \
|
||||||
|
--publish 8000:8000 \
|
||||||
--volume ${PWD}:/docs \
|
--volume ${PWD}:/docs \
|
||||||
--name iptv-docs-dev \
|
--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:
|
site:
|
||||||
@echo "Wait until mkdocs finish"
|
@echo "*** Wait until zensical finish"
|
||||||
@docker run \
|
@docker stop iptv-docs-dev 2>/dev/null; \
|
||||||
|
docker run \
|
||||||
--pull always \
|
--pull always \
|
||||||
--rm \
|
--rm \
|
||||||
--interactive \
|
--env PYTHONPATH=/docs \
|
||||||
--tty \
|
|
||||||
--volume ${PWD}:/docs \
|
--volume ${PWD}:/docs \
|
||||||
--name iptv-docs-dev \
|
--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:
|
image:
|
||||||
@docker build \
|
@docker build --tag git.axenov.dev/iptv/iptv-docs:latest:latest .
|
||||||
--tag iptv-docs:latest \
|
|
||||||
--tag git.axenov.dev/iptv/iptv-docs:latest \
|
|
||||||
.
|
|
||||||
|
|
||||||
## push: Push docker image to registry
|
## run = Run docker container from image built with `make image` on http://localhost:8001
|
||||||
push:
|
|
||||||
@docker push git.axenov.dev/iptv/iptv-docs:latest
|
|
||||||
|
|
||||||
## run: Run docker image (localhost:3001)
|
|
||||||
run:
|
run:
|
||||||
@echo "Wait until container starts and open http://localhost:3001 to see ready static website"
|
@echo "*** Wait until container starts and open http://localhost:8001 to see ready static website"
|
||||||
@docker run \
|
@docker stop iptv-docs 2>/dev/null; \
|
||||||
|
docker run \
|
||||||
--rm \
|
--rm \
|
||||||
--publish 3001:80 \
|
--publish 8001:80 \
|
||||||
--name iptv-docs \
|
--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
|
help: Makefile
|
||||||
@echo "Available recipes:"
|
@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)
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 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: 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 |
|
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 |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -262,23 +262,23 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
|||||||
### Просят денег и/или подписку
|
### Просят денег и/или подписку
|
||||||
|
|
||||||
??? quote "[Скриншот] Уважаемый клиент! Для возобновления просмотра Вам необходимо использовать не более 2 устройств"
|
??? quote "[Скриншот] Уважаемый клиент! Для возобновления просмотра Вам необходимо использовать не более 2 устройств"
|
||||||

|

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

|

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

|

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

|

|
||||||
> Вы превысили разрешённое количество одновременных подключений
|
> Вы превысили разрешённое количество одновременных подключений
|
||||||
> Для возобновления просмотра ограничьте количество подключённых устройств
|
> Для возобновления просмотра ограничьте количество подключённых устройств
|
||||||
|
|
||||||
@@ -300,11 +300,11 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
|
|||||||
### Wink
|
### Wink
|
||||||
|
|
||||||
??? quote "[Скриншот] Просмотр ТВ-каналов, фильмов и сериалов доступен только в официальных приложениях Wink и на территории России"
|
??? quote "[Скриншот] Просмотр ТВ-каналов, фильмов и сериалов доступен только в официальных приложениях Wink и на территории России"
|
||||||

|

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

|

|
||||||
> Wink ещё не показывает видео на этой территории
|
> Wink ещё не показывает видео на этой территории
|
||||||
|
|
||||||
**Решение 1:** купить подписку Wink и использовать официальные приложения.
|
**Решение 1:** купить подписку Wink и использовать официальные приложения.
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
icon: material/home
|
icon: material/home
|
||||||
|
hide: [navigation, toc]
|
||||||
---
|
---
|
||||||
|
|
||||||
# :material-home: Введение
|
# :material-home: Введение
|
||||||
@@ -9,11 +10,9 @@ icon: material/home
|
|||||||
|
|
||||||
!!! info "Все необходимые адреса"
|
!!! info "Все необходимые адреса"
|
||||||
**Веб-сайт:** [m3u.su](https://m3u.su)
|
**Веб-сайт:** [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)
|
Исходный код: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV)
|
||||||
Telegram-канал: [@iptv_aggregator](https://t.me/iptv_aggregator)
|
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 у своего провайдера или поставщиков контента.
|
Далеко не все пользователи, желающие использовать цифровое ТВ, могут позволить себе подключение IPTV у своего провайдера или поставщиков контента.
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ tags: ["сайт"]
|
|||||||
Так выглядит статусная страница сервиса.
|
Так выглядит статусная страница сервиса.
|
||||||
Попасть на неё можно по ссылке "[Аптайм](https://status.m3u.su)" в шапке сайта.
|
Попасть на неё можно по ссылке "[Аптайм](https://status.m3u.su)" в шапке сайта.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Здесь отображается состояние компонентов сервиса:
|
Здесь отображается состояние компонентов сервиса:
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ tags: ["сайт"]
|
|||||||
|
|
||||||
Можно нажать на незвание сервиса и посмотреть детальную информацию:
|
Можно нажать на незвание сервиса и посмотреть детальную информацию:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Если на шкале появляется красное деление, значит был кратковременный сбой.
|
Если на шкале появляется красное деление, значит был кратковременный сбой.
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ icon: material/book-open-page-variant-outline
|
|||||||
4. справа — содержание конкретной страницы.
|
4. справа — содержание конкретной страницы.
|
||||||
|
|
||||||
??? info end "На мобильниках содержание страницы спрятано за этой кнопкой в боковом меню:"
|
??? info end "На мобильниках содержание страницы спрятано за этой кнопкой в боковом меню:"
|
||||||

|

|
||||||
|
|
||||||
## Связанные статьи
|
## Связанные статьи
|
||||||
|
|
||||||
@@ -33,17 +33,17 @@ tags: ["плееры"]
|
|||||||
Универсальный плеер практически для любого мультимедиа-контента.
|
Универсальный плеер практически для любого мультимедиа-контента.
|
||||||
|
|
||||||
??? quote "[Скриншот] Главное окно"
|
??? quote "[Скриншот] Главное окно"
|
||||||

|

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

|

|
||||||

|

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

|

|
||||||

|

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

|

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

|

|
||||||

|

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

|

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

|

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

|

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

|

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

|

|
||||||

|

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

|

|
||||||

|

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

|

|
||||||

|

|
||||||
|
|
||||||
И дальше те же шаги 3-5 на скриншотах выше.
|
И дальше те же шаги 3-5 на скриншотах выше.
|
||||||
|
|
||||||
@@ -202,16 +202,16 @@ tags: ["плееры"]
|
|||||||
Программу передач нужно [подключать отдельной ссылкой](../faq.md#epg), из плейлиста не тянет.
|
Программу передач нужно [подключать отдельной ссылкой](../faq.md#epg), из плейлиста не тянет.
|
||||||
|
|
||||||
??? quote "[Скриншот] Главный экран"
|
??? quote "[Скриншот] Главный экран"
|
||||||

|

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

|

|
||||||

|

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

|

|
||||||

|

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

|

|
||||||

|

|
||||||
|
|
||||||
Продолжение текста, lorem ipsum dolor sit amet.
|
Продолжение текста, lorem ipsum dolor sit amet.
|
||||||
Продолжение текста, 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,221 @@
|
|||||||
|
---
|
||||||
|
# icon: material/architecture
|
||||||
|
tags: ["iptvc", "разработка", "архитектура"]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Архитектура iptvc
|
||||||
|
|
||||||
|
Внутреннее устройство программы для разработчиков.
|
||||||
|
|
||||||
|
## Стек технологий
|
||||||
|
|
||||||
|
- **Go 1.22+** — язык программирования;
|
||||||
|
- `net/http` — HTTP-сервер (Go 1.22 routing patterns);
|
||||||
|
- `html/template` — шаблоны HTML;
|
||||||
|
- `//go:embed` — встраивание шаблонов в бинарник;
|
||||||
|
- `github.com/spf13/cobra` — CLI-фреймворк;
|
||||||
|
- `gopkg.in/yaml.v3` — парсинг `config.yml`;
|
||||||
|
- `github.com/joho/godotenv` — загрузка `.env`;
|
||||||
|
- `github.com/redis/go-redis/v9` — клиент KeyDB/Redis.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
iptvc/
|
||||||
|
├── main.go # точка входа
|
||||||
|
├── config.yml # конфигурация
|
||||||
|
├── .env # переменные окружения (опционально)
|
||||||
|
├── cmd/ # CLI-команды (Cobra)
|
||||||
|
│ ├── root.go # корневая команда, глобальные флаги
|
||||||
|
│ ├── check.go # команда check
|
||||||
|
│ ├── serve.go # команда serve
|
||||||
|
│ ├── flags.go # общие флаги check/serve
|
||||||
|
│ └── version.go # команда version
|
||||||
|
├── app/
|
||||||
|
│ ├── app.go # глобальные переменные: Args, Config, Cache
|
||||||
|
│ ├── config/
|
||||||
|
│ │ └── config.go # Config, Init(), validate(), IntRange, UserAgents
|
||||||
|
│ ├── checker/
|
||||||
|
│ │ └── checker.go # CheckPlaylists(), CheckChannels(), OnPlaylistChecked
|
||||||
|
│ ├── playlist/
|
||||||
|
│ │ └── playlist.go # Playlist, Channel, Parse(), Download()
|
||||||
|
│ ├── inifile/
|
||||||
|
│ │ └── inifile.go # чтение playlists.ini
|
||||||
|
│ ├── tagfile/
|
||||||
|
│ │ └── tagfile.go # чтение channels.json, назначение тегов
|
||||||
|
│ ├── cache/
|
||||||
|
│ │ └── cache.go # подключение к KeyDB/Redis
|
||||||
|
│ ├── logger/
|
||||||
|
│ │ └── logger.go # настройка логирования
|
||||||
|
│ ├── utils/
|
||||||
|
│ │ └── utils.go # Fetch(), ExpandPath(), ArrayUnique(), Md5str()
|
||||||
|
│ └── web/
|
||||||
|
│ ├── server.go # Server, Start(), StartBackgroundChecker()
|
||||||
|
│ ├── handlers.go # HTTP-обработчики
|
||||||
|
│ ├── templates.go # TemplateManager, //go:embed
|
||||||
|
│ └── views/ # HTML-шаблоны
|
||||||
|
│ ├── layout.html
|
||||||
|
│ ├── list.html
|
||||||
|
│ └── details.html
|
||||||
|
└── go.mod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Пакеты
|
||||||
|
|
||||||
|
### `app`
|
||||||
|
|
||||||
|
Глобальный контейнер: `Args` (CLI-флаги), `Config` (конфигурация), `Cache` (Redis-клиент).
|
||||||
|
`Init()` загружает конфигурацию, инициализирует логгер и подключение к кешу.
|
||||||
|
|
||||||
|
### `app.config`
|
||||||
|
|
||||||
|
Структуры: `Config` → `AppConfig`, `ServerConfig`, `CheckConfig`, `CacheConfig`.
|
||||||
|
|
||||||
|
Кастомные YAML-типы:
|
||||||
|
|
||||||
|
- **`IntRange`** — скаляр или `[min, max]`. Метод `Value()` возвращает константу или случайное значение.
|
||||||
|
- **`UserAgents`** — строка или массив строк. Метод `Pick()` возвращает случайный элемент.
|
||||||
|
|
||||||
|
`Init(configPath)` — загружает `config.yml`, применяет env, валидирует.
|
||||||
|
|
||||||
|
`validate()` — проверяет все значения, исправляет некорректные с логированием.
|
||||||
|
|
||||||
|
### `app.checker`
|
||||||
|
|
||||||
|
Содержит логику проверки:
|
||||||
|
|
||||||
|
- **`PrepareListsToCheck(files, urls, codes)`** — формирует список плейлистов из файлов, URL и кодов ini-файла.
|
||||||
|
- **`CheckPlaylists(lists)`** — параллельная проверка плейлистов (семфор `per-routine`), загрузка, парсинг, вызов `CheckChannels` для каждого.
|
||||||
|
- **`CheckChannels(pls)`** — параллельная проверка каналов (семфор `per-routine`), HTTP-запрос с `Range` header.
|
||||||
|
- **`OnPlaylistChecked`** — глобальный callback, вызывается после проверки каждого плейлиста. Используется веб-сервером для обновления in-memory кеша.
|
||||||
|
- **`cachePlaylist(pls)`** — сохранение результата в Redis (если включён).
|
||||||
|
|
||||||
|
Параметры проверки берутся из `app.Config.Check.Playlists` и `app.Config.Check.Channels`.
|
||||||
|
|
||||||
|
### `app.playlist`
|
||||||
|
|
||||||
|
- **`Playlist`** — плейлист: код, URL, контент, каналы, статус.
|
||||||
|
- **`Channel`** — канал: ID, название, URL, статус, теги.
|
||||||
|
- **`Download(userAgent, timeout)`** — загрузка по URL.
|
||||||
|
- **`ReadFromFs()`** — чтение из файла.
|
||||||
|
- **`Parse()`** — парсинг m3u/m3u8 контента.
|
||||||
|
|
||||||
|
### `app.web`
|
||||||
|
|
||||||
|
Веб-сервер на `net/http` (Go 1.22 routing).
|
||||||
|
|
||||||
|
- **`Server`** — структура: конфиг, кеш, шаблоны, in-memory кеш (`memCache` с `sync.RWMutex`).
|
||||||
|
- **`Start()`** — запуск HTTP-сервера.
|
||||||
|
- **`StartBackgroundChecker(opts)`** — фоновая проверка в отдельной горутине.
|
||||||
|
- **`CheckOptions`** — параметры: Every, Repeat, Random, Files, Urls, Codes.
|
||||||
|
|
||||||
|
Маршруты (Go 1.22 patterns):
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/playlists/{code} — JSON плейлиста
|
||||||
|
GET /api/version — версия
|
||||||
|
GET /api/health — здоровье сервиса
|
||||||
|
GET /api/stats — статистика
|
||||||
|
GET /{$} — главная (catch-all root)
|
||||||
|
GET /{path...} — все остальные маршруты (catch-all)
|
||||||
|
```
|
||||||
|
|
||||||
|
Catch-all `/{path...}` используется для избежания конфликтов паттернов в Go 1.22 mux.
|
||||||
|
|
||||||
|
In-memory кеш (`memCache`) обновляется через `OnPlaylistChecked` callback.
|
||||||
|
Это позволяет отображать результаты проверки в реальном времени без ожидания завершения цикла и без Redis.
|
||||||
|
|
||||||
|
ini-файл кешируется на 30 секунд, кеш сбрасывается при каждом обновлении `memCache`.
|
||||||
|
|
||||||
|
## Жизненный цикл `serve --check`
|
||||||
|
|
||||||
|
```
|
||||||
|
main → app.Init() → web.NewServer() → go StartBackgroundChecker() → server.Start()
|
||||||
|
|
||||||
|
StartBackgroundChecker:
|
||||||
|
loop:
|
||||||
|
runCheckerOnce()
|
||||||
|
→ checker.PrepareListsToCheck()
|
||||||
|
→ checker.CheckPlaylists()
|
||||||
|
→ for each playlist (parallel, per-routine):
|
||||||
|
→ Download() / ReadFromFs()
|
||||||
|
→ Parse()
|
||||||
|
→ CheckChannels()
|
||||||
|
→ for each channel (parallel, per-routine):
|
||||||
|
→ HTTP GET with Range header
|
||||||
|
→ check status + content type
|
||||||
|
→ OnPlaylistChecked(pls) → memCache update
|
||||||
|
→ one-cooldown sleep
|
||||||
|
→ all-cooldown sleep
|
||||||
|
sleep(every)
|
||||||
|
if repeat > 0 && iteration >= repeat: stop
|
||||||
|
```
|
||||||
|
|
||||||
|
## CLI-флаги
|
||||||
|
|
||||||
|
### Общие (`cmd/flags.go`)
|
||||||
|
|
||||||
|
Используются командами `check` и `serve --check`:
|
||||||
|
|
||||||
|
| Флаг | Поле | Описание |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `-i, --ini` | `Args.IniPath` | Путь к playlists.ini |
|
||||||
|
| `-t, --tags` | `Args.TagsPath` | Путь к channels.json |
|
||||||
|
| `-r, --random` | `Args.RandomCount` | Случайные N плейлистов |
|
||||||
|
| `--repeat` | `Args.RepeatCount` | Количество циклов (0 = бесконечно) |
|
||||||
|
| `--every` | `Args.RepeatEverySec` | Секунд между циклами |
|
||||||
|
|
||||||
|
### Только `check` (`addCheckOnlyFlags`)
|
||||||
|
|
||||||
|
| Флаг | Поле | Описание |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `-j, --json` | `Args.NeedJson` | Вывод в JSON |
|
||||||
|
| `-q, --quiet` | `Args.NeedQuiet` | Подавить логи |
|
||||||
|
| `-f, --file` | `Args.Files` | Локальные m3u файлы |
|
||||||
|
| `-u, --url` | `Args.Urls` | URL плейлистов |
|
||||||
|
| `-c, --code` | `Args.Codes` | Коды из ini-файла |
|
||||||
|
|
||||||
|
### Только `serve`
|
||||||
|
|
||||||
|
| Флаг | Поле | Описание |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `-p, --port` | `Args.ServerPort` | Порт веб-сервера |
|
||||||
|
| `--host` | `Args.ServerHost` | Хост привязки |
|
||||||
|
| `--check` | `Args.NeedCheck` | Включить фоновую проверку |
|
||||||
|
|
||||||
|
### Глобальные (`cmd/root.go`)
|
||||||
|
|
||||||
|
| Флаг | Поле | Описание |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `--config` | `Args.ConfigPath` | Путь к config.yml |
|
||||||
|
| `-v, --verbose` | `Args.Verbose` | Подробный лог |
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Подробное описание параметров — в разделе [config.yml](../config.md).
|
||||||
|
|
||||||
|
Приоритет: Defaults < `config.yml` < Env < CLI-флаги.
|
||||||
|
|
||||||
|
CLI-флаги переопределяют конфигурацию только если переданы явно (`cmd.Flags().Changed()`).
|
||||||
|
Для этого в Cobra используются zero-value defaults (0, "", false), чтобы отличить «не передан» от «передан со значением по умолчанию».
|
||||||
|
|
||||||
|
## Шаблоны
|
||||||
|
|
||||||
|
HTML-шаблоны встроены через `//go:embed`:
|
||||||
|
|
||||||
|
- `layout.html` — общий каркас (header, footer);
|
||||||
|
- `list.html` — список плейлистов с пагинацией;
|
||||||
|
- `details.html` — детали плейлиста и список каналов.
|
||||||
|
|
||||||
|
SVG-логотипы каналов передаются через `encodeURIComponent` в data-URI для корректной работы с кавычками в HTML.
|
||||||
|
|
||||||
|
При отсутствии `playlists.ini` рендерится пустое состояние с alert-блоком.
|
||||||
|
|
||||||
|
## Кеширование
|
||||||
|
|
||||||
|
Два уровня кеша:
|
||||||
|
|
||||||
|
1. **Redis/KeyDB** (опционально) — постоянный кеш результатов проверки. TTL из `cache.ttl`.
|
||||||
|
2. **In-memory** (`memCache`) — только при `serve --check`. Обновляется в реальном времени через callback. Не требует Redis.
|
||||||
|
|
||||||
|
In-memory кеш приоритетнее Redis при отображении в веб-интерфейсе.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
title: channels.json
|
||||||
icon: material/code-json
|
icon: material/code-json
|
||||||
tags: ["iptvc", "теги", "каналы"]
|
tags: ["iptvc", "теги", "каналы"]
|
||||||
---
|
---
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
title: "*.m3u (*.m3u8)"
|
||||||
icon: material/playlist-play
|
icon: material/playlist-play
|
||||||
tags: ["плейлисты", "каналы"]
|
tags: ["плейлисты", "каналы"]
|
||||||
---
|
---
|
||||||
@@ -15,6 +16,7 @@ tags: ["плейлисты", "каналы"]
|
|||||||
После директив с новой строки указывается ссылка на канал (или путь к файлу).
|
После директив с новой строки указывается ссылка на канал (или путь к файлу).
|
||||||
|
|
||||||
В свою чередь, по этой ссылке может быть:
|
В свою чередь, по этой ссылке может быть:
|
||||||
|
|
||||||
* либо текстовое представление контента в формате m3u/m3u8/XMLTV/MPD с описанием непосредственно участки трансляции;
|
* либо текстовое представление контента в формате m3u/m3u8/XMLTV/MPD с описанием непосредственно участки трансляции;
|
||||||
* либо непосредственно сама потоковая трансляция mp4 или т. п.
|
* либо непосредственно сама потоковая трансляция mp4 или т. п.
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
title: playlists.ini
|
||||||
icon: material/code-brackets
|
icon: material/code-brackets
|
||||||
tags: ["плейлисты"]
|
tags: ["плейлисты"]
|
||||||
---
|
---
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
icon: material/download
|
||||||
|
tags: ["iptvc"]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Установка и запуск
|
||||||
|
|
||||||
|
## Запуск готовой программы
|
||||||
|
|
||||||
|
Достаточно скачать и распаковать архив с подходящим исполняемым файлом [со страницы последнего релиза][rel_page] в любую удобную директорию:
|
||||||
|
|
||||||
|
| ОС | Скачать для `amd64` | Скачать для `arm64` |
|
||||||
|
| ------- | ---------------------------------- | ---------------------------------- |
|
||||||
|
| Linux | [linux_amd64.zip][linux_amd64] | [linux_arm64.zip][linux_arm64] |
|
||||||
|
| MacOS | [darwin_amd64.zip][darwin_amd64] | [darwin_arm64.zip][darwin_arm64] |
|
||||||
|
| Windows | [windows_amd64.zip][windows_amd64] | [windows_arm64.zip][windows_arm64] |
|
||||||
|
|
||||||
|
[rel_page]: https://git.axenov.dev/IPTV/iptvc/releases/latest
|
||||||
|
[linux_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_amd64.zip
|
||||||
|
[linux_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/linux_arm64.zip
|
||||||
|
[darwin_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_amd64.zip
|
||||||
|
[darwin_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/darwin_arm64.zip
|
||||||
|
[windows_amd64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_amd64.zip
|
||||||
|
[windows_arm64]: https://git.axenov.dev/IPTV/iptvc/releases/download/latest/windows_arm64.zip
|
||||||
|
|
||||||
|
## Запуск релизного образа
|
||||||
|
|
||||||
|
Релизные docker-образы строятся для платформы `linux` и архитектуры `amd64`.
|
||||||
|
|
||||||
|
Найти их можно здесь: <https://git.axenov.dev/IPTV/-/packages/container/iptvc>
|
||||||
|
|
||||||
|
Тег `latest` всегда соответствует последней версии, он подразумевается по умолчанию:
|
||||||
|
|
||||||
|
=== "Запуск последней версии"
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run \
|
||||||
|
--pull always \
|
||||||
|
--name iptvc \
|
||||||
|
git.axenov.dev/iptv/iptvc \ #(1)!
|
||||||
|
КОМАНДА [АРГУМЕНТЫ]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Подразумевается `:latest`, можно указать явно
|
||||||
|
|
||||||
|
=== "Запуск другой версии"
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run \
|
||||||
|
--pull always \
|
||||||
|
--name iptvc \
|
||||||
|
git.axenov.dev/iptv/iptvc:v1.0.6 \ #(1)!
|
||||||
|
КОМАНДА [АРГУМЕНТЫ]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Список версий доступен на [релизной странице][rel_page]
|
||||||
|
|
||||||
|
## Использование образа в Docker compose
|
||||||
|
|
||||||
|
```yaml title="compose.yml"
|
||||||
|
services:
|
||||||
|
#...
|
||||||
|
iptvc:
|
||||||
|
container_name: iptvc
|
||||||
|
image: git.axenov.dev/iptv/iptvc:latest
|
||||||
|
command: [serve] #(1)!
|
||||||
|
#...
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Доступные команды и аргументы см. в [**Справочнике команд**](commands/index.md)
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
---
|
---
|
||||||
icon: material/check-network
|
title: Введение
|
||||||
|
icon: octicons/sparkles-fill-16
|
||||||
hide: [toc]
|
hide: [toc]
|
||||||
---
|
---
|
||||||
|
|
||||||
# :material-check-network: IPTV Checker (iptvc)
|
# IPTV Checker (iptvc)
|
||||||
|
|
||||||
Это простая программа для проверки IPTV плейлистов, входящая в состав проекта m3u.su.
|
Это простая программа для проверки IPTV плейлистов, входящая в состав проекта m3u.su.
|
||||||
|
|
||||||
@@ -11,26 +12,47 @@ hide: [toc]
|
|||||||
|
|
||||||
> Программа не предназначена для хранения, воспроизведения или распространения пиратского контента.
|
> Программа не предназначена для хранения, воспроизведения или распространения пиратского контента.
|
||||||
|
|
||||||
Программа не имеет графического интерфейса и работает в терминале.
|
|
||||||
|
|
||||||
<div class="grid cards" markdown>
|
<div class="grid cards" markdown>
|
||||||
- [:material-flag-checkered: Быстрый старт](quickstart.md)
|
- :material-flag-checkered: **Быстрый старт**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Коротко о главном, если не терпится
|
Коротко о главном, если не терпится
|
||||||
|
|
||||||
- [:octicons-terminal-24: Доступные команды](commands/index.md)
|
[Подробности :material-arrow-right:][start]{ .md-button .md-button--primary }
|
||||||
|
|
||||||
|
- :material-application-brackets-outline: **Запуск сайта**
|
||||||
|
|
||||||
---
|
---
|
||||||
Как правильно с ней работать
|
|
||||||
|
|
||||||
- [:simple-dotenv: Переменные окружения](env.md)
|
Создайте свой агрегатор плейлистов
|
||||||
|
|
||||||
|
[Подробности :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>
|
</div>
|
||||||
|
|
||||||
## :material-cog-sync-outline: Как работает iptvc
|
[start]: quickstart.md "Перейти к разделу"
|
||||||
|
[site]: site/index.md "Перейти к разделу"
|
||||||
|
[cli]: commands/index.md "Перейти к разделу"
|
||||||
|
[cfg]: config/config.md "Перейти к разделу"
|
||||||
|
|
||||||
|
<!--
|
||||||
|
## :material-cog-sync-outline: Как работает `iptvc`
|
||||||
|
|
||||||
Принцип её работы очень простой:
|
Принцип её работы очень простой:
|
||||||
|
|
||||||
@@ -48,3 +70,4 @@ hide: [toc]
|
|||||||
|
|
||||||
Подробности см. в разделе [Команда `check`](../iptvc/commands/check.md).
|
Подробности см. в разделе [Команда `check`](../iptvc/commands/check.md).
|
||||||
|
|
||||||
|
-->
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
icon: material/flag-checkered
|
||||||
|
tags: ["iptvc"]
|
||||||
|
---
|
||||||
|
|
||||||
|
# :material-flag-checkered: Быстрый старт
|
||||||
|
|
||||||
|
Для простоты представим, что программа скачана и распакована в любую директорию и вы находитесь в ней.
|
||||||
|
|
||||||
|
Используйте тот способ запуска, который выбрали на шаге [установки](install.md).
|
||||||
|
|
||||||
|
Ниже представлены лишь частые примеры запуска программы с разными аргументами под разные случаи.
|
||||||
|
|
||||||
|
## Проверить плейлист по прямой ссылке
|
||||||
|
|
||||||
|
```
|
||||||
|
./iptvc check -u https://example.com/pls.m3u
|
||||||
|
./iptvc check --url https://example.com/pls.m3u
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проверить файл плейлиста с диска
|
||||||
|
|
||||||
|
```
|
||||||
|
./iptvc check -f /home/user/pls.m3u
|
||||||
|
./iptvc check --file /home/user/pls.m3u
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проверить плейлист по короткому коду из [`playlists.ini`](formats/playlists.md)
|
||||||
|
|
||||||
|
```
|
||||||
|
./iptvc check -c X
|
||||||
|
./iptvc check --code X
|
||||||
|
```
|
||||||
|
|
||||||
|
Файл `playlists.ini` должен лежать рядом с `iptvc`.
|
||||||
|
|
||||||
|
Если файл лежит в другой директории, то можно явно указать путь к нему:
|
||||||
|
|
||||||
|
```
|
||||||
|
./iptvc check --ini /home/user/playlists.ini --code X
|
||||||
|
```
|
||||||
|
|
||||||
|
Если ini-файл не будет найден, программа предупредит об этом.
|
||||||
|
|
||||||
|
## Присвоить каналам тематические теги
|
||||||
|
|
||||||
|
Для этого рядом с `iptvc` должен лежать файл [channels.json](formats/channels.md).
|
||||||
|
|
||||||
|
Если файл лежит в другой директории, то можно указать её явно:
|
||||||
|
|
||||||
|
```
|
||||||
|
./iptvc check --tags /home/user/channels.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Если json-файл не будет найден, то программа предупредит о том, что теги не будут присвоены, и продолжит работу.
|
||||||
|
|
||||||
|
## Проверить несколько плейлистов одновременно
|
||||||
|
|
||||||
|
Для этого можно комбинировать все аргументы, перечисленные выше, с учётом особенностей их работы:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./iptvc check \
|
||||||
|
--ini /home/user/p.ini \ #(1)!
|
||||||
|
--tags /home/user/c.json \ #(2)!
|
||||||
|
--code Y \ #(3)!
|
||||||
|
--file /home/user/tv.m3u \ #(4)!
|
||||||
|
--url https://example.com/pls1.m3u \ #(5)!
|
||||||
|
-u https://example.com/pls2.m3u #(6)!
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Из этого файла будет взят список плейлистов
|
||||||
|
2. Из этого файла будут взяты правила для присвоения тегов каналам
|
||||||
|
3. Из ini-списка будет проверен только плейлист с кодом `Y`
|
||||||
|
4. Это отдельный файл плейлиста на диске, который будет проверен в дополнение к основному списку
|
||||||
|
5. Плейлист на каком-то удалённом сервере, который будет загружен и проверен вместе с прошлыми двумя
|
||||||
|
6. Ещё один по ссылке, просто через короткий вариант аргумента `--url`
|
||||||
|
|
||||||
|
Символ `\` нужен только для наглядного разделения аргументов на несколько строк.
|
||||||
|
Всё это можно писать в одну строку.
|
||||||
|
|
||||||
|
Переданные плейлисты будут обработаны в следующем порядке:
|
||||||
|
|
||||||
|
1. локальные файлы (`-f|--file`);
|
||||||
|
2. по ссылкам (`-u|--url`);
|
||||||
|
3. по кодам из ini-файла (`-i|--ini`, `-c|--code`).
|
||||||
@@ -15,7 +15,7 @@ tags: ["сайт", "статусы", "каналы"]
|
|||||||
|
|
||||||
## Вкладка "Основная информация"
|
## Вкладка "Основная информация"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
На этой вкладке выводится таблица со следующими строками:
|
На этой вкладке выводится таблица со следующими строками:
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ tags: ["сайт", "статусы", "каналы"]
|
|||||||
Если при проверке плейлиста возникла ошибка, то она будет отображена красным цветом сразу под заголовком:
|
Если при проверке плейлиста возникла ошибка, то она будет отображена красным цветом сразу под заголовком:
|
||||||
|
|
||||||
??? quote "Скриншот страницы с ошибкой"
|
??? quote "Скриншот страницы с ошибкой"
|
||||||

|

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

|

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

|

|
||||||
|
|
||||||
В списке всегда отображается не более 100 каналов.
|
В списке всегда отображается не более 100 каналов.
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ tags: ["сайт", "статусы", "каналы"]
|
|||||||
**Сбросить** выбор можно повторным нажатием на каждый, либо кнопкой сброса у строки поиска.
|
**Сбросить** выбор можно повторным нажатием на каждый, либо кнопкой сброса у строки поиска.
|
||||||
|
|
||||||
??? quote "Пример фильтрации"
|
??? quote "Пример фильтрации"
|
||||||

|

|
||||||
|
|
||||||
<a id="shortlink"></a>
|
<a id="shortlink"></a>
|
||||||
## Ссылка для ТВ
|
## Ссылка для ТВ
|
||||||
@@ -7,7 +7,7 @@ tags: ["сайт", "плейлисты"]
|
|||||||
|
|
||||||
Это главная страница сайта.
|
Это главная страница сайта.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Наверху отображаются:
|
Наверху отображаются:
|
||||||
|
|
||||||
@@ -33,4 +33,4 @@ tags: ["сайт", "плейлисты"]
|
|||||||
|
|
||||||
В зависимости от ширины экрана, для экономии места может быть скрыто описание с иконками возможностей и короткая ссылка.
|
В зависимости от ширины экрана, для экономии места может быть скрыто описание с иконками возможностей и короткая ссылка.
|
||||||
|
|
||||||

|

|
||||||
@@ -0,0 +1,392 @@
|
|||||||
|
---
|
||||||
|
title: Запуск своего сайта
|
||||||
|
icon: material/rocket-launch
|
||||||
|
tags: ["iptvc", "serve", "сайт"]
|
||||||
|
---
|
||||||
|
|
||||||
|
# :material-rocket-launch: Запуск своего сайта
|
||||||
|
|
||||||
|
В этой статье мы шаг за шагом запустим собственный сайт-агрегатор IPTV-плейлистов — от простейшего варианта до полной конфигурации с кешем и тонкой настройкой проверки.
|
||||||
|
|
||||||
|
Программа `iptvc` уже должна быть [установлена](../install.md). Все команды ниже выполняются в терминале из директории, где лежит бинарник.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 1. Запускаем пустой сайт
|
||||||
|
|
||||||
|
Минимальный запуск — одна команда:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Сайт откроется на `http://localhost:8080`. Это пустая страница: нет ни одного плейлиста, потому что программе пока неоткуда их взять.
|
||||||
|
|
||||||
|
Чтобы изменить порт или хост, не трогая файл конфигурации:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve -p 3000 --host 0.0.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробнее об этих флагах — в [документации команды `serve`](../commands/serve.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 2. Добавляем плейлисты
|
||||||
|
|
||||||
|
Список плейлистов описывается в файле [`playlists.ini`](../formats/playlists.md). Создадим его рядом с `iptvc`:
|
||||||
|
|
||||||
|
```ini title="playlists.ini"
|
||||||
|
[ru]
|
||||||
|
name = Российские каналы
|
||||||
|
desc = Основные федеральные каналы
|
||||||
|
pls = 'https://example.com/ru.m3u'
|
||||||
|
src = 'https://example.com/ru-playlist'
|
||||||
|
|
||||||
|
[movies]
|
||||||
|
name = Фильмы
|
||||||
|
pls = 'https://example.com/movies.m3u'
|
||||||
|
```
|
||||||
|
|
||||||
|
Каждая секция `[code]` — это плейлист. Код используется в коротких ссылках вида `http://localhost:8080/ru`. Параметр `pls` обязателен, остальные — по желанию.
|
||||||
|
|
||||||
|
Теперь запустим:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Сайт покажет оба плейлиста, но их статус — `unknown` (неизвестно). Это нормально: программа знает о них, но ещё не проверяла. Чтобы статусы появились, нужно включить фоновую проверку.
|
||||||
|
|
||||||
|
!!! tip "Путь к ini-файлу"
|
||||||
|
Если файл лежит не рядом с программой, укажите путь через флаг [`-i`](../commands/serve.md#ini) или в [`config.yml`](../config/config.md) → `app.playlists`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 3. Включаем фоновую проверку
|
||||||
|
|
||||||
|
Без проверки сайт просто показывает список. Чтобы плейлисты и каналы проверялись автоматически, добавим флаг `--check`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Теперь программа в фоне загружает каждый плейлист, парсит каналы и проверяет их доступность. Результаты сразу попадают в оперативную память и отображаются на сайте.
|
||||||
|
|
||||||
|
Можно настроить интервал между циклами проверки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# проверять каждые 120 секунд, бесконечно
|
||||||
|
./iptvc serve --check --every 120
|
||||||
|
|
||||||
|
# проверить один раз и остановить
|
||||||
|
./iptvc serve --check --repeat 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Если не хочется каждый раз писать `--check`, можно включить проверку через [`config.yml`](../config/config.md):
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
check:
|
||||||
|
start-on-serve: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Тогда обычный `./iptvc serve` автоматически запустит фоновую проверку.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 4. Настраиваем внешний вид сайта
|
||||||
|
|
||||||
|
Сайт можно настроить под себя: заголовок, иконку, навигацию в шапке и ссылки в подвале. Всё это — в секции [`site`](../config/config.md#секция-site) файла `config.yml`.
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
site:
|
||||||
|
base-url: http://localhost:8080
|
||||||
|
repo-url: https://git.axenov.dev/IPTV
|
||||||
|
page-size: 20 # пагинация по 20 плейлистов на страницу (0 — без пагинации)
|
||||||
|
favicon: /favicon.ico # путь к иконке
|
||||||
|
header:
|
||||||
|
title: Мой IPTV # заголовок в шапке и вкладке браузера
|
||||||
|
navigation:
|
||||||
|
- title: Документация
|
||||||
|
url: /docs
|
||||||
|
icon: document-text-outline
|
||||||
|
- title: Telegram
|
||||||
|
icon: paper-plane-outline
|
||||||
|
children:
|
||||||
|
- title: Канал
|
||||||
|
url: https://t.me/my_channel
|
||||||
|
icon: megaphone-outline
|
||||||
|
- title: Чат
|
||||||
|
url: https://t.me/my_chat
|
||||||
|
icon: chatbubbles-outline
|
||||||
|
footer-links:
|
||||||
|
- title: Исходники
|
||||||
|
url: https://git.axenov.dev/IPTV
|
||||||
|
icon: code-slash-outline
|
||||||
|
- title: Мой сайт
|
||||||
|
url: https://example.com
|
||||||
|
icon: person-outline
|
||||||
|
```
|
||||||
|
|
||||||
|
--8<-- "ionicons-name.md"
|
||||||
|
|
||||||
|
!!! note "base-url"
|
||||||
|
Параметр `base-url` используется для формирования внутренних ссылок. Если публикуете сайт на домене, укажите его здесь, например `https://my-iptv.ru`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 5. Добавляем теги каналам
|
||||||
|
|
||||||
|
Теги помогают посетителям находить каналы по темам: спорт, фильмы, музыка и так далее. Правила описываются в файле [`channels.json`](../formats/channels.md).
|
||||||
|
|
||||||
|
```json title="channels.json"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"tvg-id": "^ru-",
|
||||||
|
"tags": ["russian"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "спорт",
|
||||||
|
"tags": ["sport"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "кино|фильм",
|
||||||
|
"tags": ["film"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Путь к файлу указывается в [`config.yml`](../config/config.md) → `app.tags` или через флаг [`-t`](../commands/serve.md#tags):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve --check -t /path/to/channels.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Полный список доступных тегов — в [справочнике по channels.json](../formats/channels.md#доступные-теги).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 6. Подключаем кеш (KeyDB/Redis)
|
||||||
|
|
||||||
|
По умолчанию результаты проверки хранятся только в оперативной памяти. Если программу перезапустить — все результаты пропадут, и плейлисты снова станут `unknown` до следующей проверки.
|
||||||
|
|
||||||
|
Кеш решает эту проблему: результаты сохраняются в KeyDB (или Redis) и переживают перезапуск. Включается одной строкой в [`config.yml`](../config/config.md#секция-cache):
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
ttl: 1800 # секунды (30 минут)
|
||||||
|
```
|
||||||
|
|
||||||
|
Или через переменные окружения:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CACHE_ENABLED=true CACHE_TTL=3600 ./iptvc serve --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Или через флаги:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve --check --cache-enabled --cache-host 192.168.1.10 --cache-ttl 3600
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip "KeyDB или Redis"
|
||||||
|
KeyDB — это форк Redis, полностью совместимый по протоколу. Подойдёт любой из них. Если кеш включён, но сервер недоступен — сайт продолжит работать, просто без кеширования.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Шаг 7. Тонкая настройка проверки
|
||||||
|
|
||||||
|
Когда плейлистов много, полезно управлять параллелизмом, таймаутами и задержками. Все параметры — в секции [`check`](../config/config.md#секция-check) файла `config.yml`.
|
||||||
|
|
||||||
|
### Параллелизм
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
check:
|
||||||
|
playlists:
|
||||||
|
max-routines: 10 # сколько плейлистов проверять одновременно
|
||||||
|
per-routine: 5 # сколько плейлистов в одной процедуре
|
||||||
|
channels:
|
||||||
|
max-routines: 100 # сколько каналов проверять одновременно
|
||||||
|
per-routine: 20 # сколько каналов в одной процедуре
|
||||||
|
```
|
||||||
|
|
||||||
|
Чем больше значения — тем быстрее проверка, но выше нагрузка на процессор и сеть. Начните со значений по умолчанию и увеличивайте при необходимости.
|
||||||
|
|
||||||
|
### Таймауты
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
check:
|
||||||
|
playlists:
|
||||||
|
timeout: 10000 # мс на загрузку плейлиста
|
||||||
|
channels:
|
||||||
|
timeout: 10000 # мс на проверку одного канала
|
||||||
|
byte-range: 512 # сколько байт скачать от сервера канала
|
||||||
|
```
|
||||||
|
|
||||||
|
Если плейлисты или каналы медленные, увеличьте `timeout`. Если сервер блокирует большие запросы — уменьшите `byte-range`.
|
||||||
|
|
||||||
|
### Задержки (cooldown)
|
||||||
|
|
||||||
|
Чтобы не перегружать серверы-источники, между проверками можно делать паузы. Параметры поддерживают как фиксированное значение, так и диапазон `[min, max]` — тогда пауза будет случайной при каждом проходе:
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
check:
|
||||||
|
playlists:
|
||||||
|
all-cooldown: 5000 # 5 секунд после всех плейлистов
|
||||||
|
one-cooldown: [1000, 3000] # 1–3 секунды после каждого плейлиста
|
||||||
|
channels:
|
||||||
|
cooldown: [100, 500] # 100–500 мс после каждого канала
|
||||||
|
```
|
||||||
|
|
||||||
|
### User-Agent
|
||||||
|
|
||||||
|
Некоторые серверы блокируют запросы без правильного User-Agent. Можно указать один или несколько — тогда при каждом запросе будет выбран случайный:
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
check:
|
||||||
|
playlists:
|
||||||
|
user-agent:
|
||||||
|
- Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||||
|
- Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||||
|
channels:
|
||||||
|
user-agent: Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||||
|
```
|
||||||
|
|
||||||
|
Все эти параметры можно также задавать через [переменные окружения](../config/env.md) или [CLI-флаги](../commands/serve.md) — они имеют наивысший приоритет.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Полный пример
|
||||||
|
|
||||||
|
Соберём всё вместе в одном `config.yml`:
|
||||||
|
|
||||||
|
```yaml title="config.yml"
|
||||||
|
app:
|
||||||
|
timezone: GMT+3
|
||||||
|
debug: false
|
||||||
|
log_level: info
|
||||||
|
playlists: ./playlists.ini
|
||||||
|
tags: ./channels.json
|
||||||
|
|
||||||
|
server:
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
site:
|
||||||
|
base-url: https://my-iptv.ru
|
||||||
|
repo-url: https://git.axenov.dev/IPTV
|
||||||
|
page-size: 20
|
||||||
|
favicon: /favicon.ico
|
||||||
|
header:
|
||||||
|
title: Мой IPTV
|
||||||
|
navigation:
|
||||||
|
- title: Статус
|
||||||
|
url: https://status.my-iptv.ru
|
||||||
|
icon: pulse-outline
|
||||||
|
- title: Документация
|
||||||
|
url: /docs
|
||||||
|
icon: document-text-outline
|
||||||
|
- title: Telegram
|
||||||
|
icon: paper-plane-outline
|
||||||
|
children:
|
||||||
|
- title: Канал
|
||||||
|
url: https://t.me/my_channel
|
||||||
|
icon: megaphone-outline
|
||||||
|
- title: Чат
|
||||||
|
url: https://t.me/my_chat
|
||||||
|
icon: chatbubbles-outline
|
||||||
|
footer-links:
|
||||||
|
- title: Исходники
|
||||||
|
url: https://git.axenov.dev/IPTV
|
||||||
|
icon: code-slash-outline
|
||||||
|
- title: Контакты
|
||||||
|
url: https://example.com
|
||||||
|
icon: person-outline
|
||||||
|
|
||||||
|
check:
|
||||||
|
start-on-serve: true
|
||||||
|
playlists:
|
||||||
|
user-agent:
|
||||||
|
- Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer
|
||||||
|
- Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||||
|
timeout: 10000
|
||||||
|
all-cooldown: 5000
|
||||||
|
one-cooldown: [1000, 3000]
|
||||||
|
max-routines: 10
|
||||||
|
per-routine: 5
|
||||||
|
channels:
|
||||||
|
user-agent: Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
|
||||||
|
timeout: 10000
|
||||||
|
byte-range: 512
|
||||||
|
cooldown: [100, 500]
|
||||||
|
max-routines: 100
|
||||||
|
per-routine: 20
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
ttl: 3600
|
||||||
|
```
|
||||||
|
|
||||||
|
Запуск:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./iptvc serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Поскольку `start-on-serve: true`, фоновая проверка запустится автоматически. Кеш включён, так что результаты переживут перезапуск. Сайт доступен на `http://0.0.0.0:8080`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Удобно запускать сайт в контейнере. Образ `iptvc` уже включает бинарник:
|
||||||
|
|
||||||
|
```yaml title="compose.yml"
|
||||||
|
services:
|
||||||
|
iptvc:
|
||||||
|
image: git.axenov.dev/iptv/iptvc:latest
|
||||||
|
command: [serve]
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./config.yml:/app/config.yml:ro
|
||||||
|
- ./playlists.ini:/app/playlists.ini:ro
|
||||||
|
- ./channels.json:/app/channels.json:ro
|
||||||
|
environment:
|
||||||
|
- CHECK_START_ON_SERVE=true
|
||||||
|
- CACHE_ENABLED=true
|
||||||
|
- CACHE_HOST=keydb
|
||||||
|
- CACHE_PORT=6379
|
||||||
|
|
||||||
|
keydb:
|
||||||
|
image: eqalpha/keydb:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробнее об установке образа — в [документации по установке](../install.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Краткая шпаргалка
|
||||||
|
|
||||||
|
| Задача | Как |
|
||||||
|
| --- | --- |
|
||||||
|
| Запустить сайт | `./iptvc serve` |
|
||||||
|
| С проверкой плейлистов | `./iptvc serve --check` |
|
||||||
|
| На другом порту | `./iptvc serve -p 3000` |
|
||||||
|
| С ini-файлом из другого места | `./iptvc serve -i /path/to/playlists.ini` |
|
||||||
|
| С кешем | `./iptvc serve --check --cache-enabled` |
|
||||||
|
| Один цикл проверки | `./iptvc serve --check --repeat 1` |
|
||||||
|
| Проверять каждые 2 минуты | `./iptvc serve --check --every 120` |
|
||||||
|
| Подробные логи | `./iptvc serve --check --verbose` |
|
||||||
|
|
||||||
|
Полный список параметров — в [справочнике по `config.yml`](../config/config.md), [переменным окружения](../config/env.md) и [команде `serve`](../commands/serve.md).
|
||||||
@@ -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'
|
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
Attribution 4.0 International
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||||
|
does not provide legal services or legal advice. Distribution of
|
||||||
|
Creative Commons public licenses does not create a lawyer-client or
|
||||||
|
other relationship. Creative Commons makes its licenses and related
|
||||||
|
information available on an "as-is" basis. Creative Commons gives no
|
||||||
|
warranties regarding its licenses, any material licensed under their
|
||||||
|
terms and conditions, or any related information. Creative Commons
|
||||||
|
disclaims all liability for damages resulting from their use to the
|
||||||
|
fullest extent possible.
|
||||||
|
|
||||||
|
Using Creative Commons Public Licenses
|
||||||
|
|
||||||
|
Creative Commons public licenses provide a standard set of terms and
|
||||||
|
conditions that creators and other rights holders may use to share
|
||||||
|
original works of authorship and other material subject to copyright
|
||||||
|
and certain other rights specified in the public license below. The
|
||||||
|
following considerations are for informational purposes only, are not
|
||||||
|
exhaustive, and do not form part of our licenses.
|
||||||
|
|
||||||
|
Considerations for licensors: Our public licenses are
|
||||||
|
intended for use by those authorized to give the public
|
||||||
|
permission to use material in ways otherwise restricted by
|
||||||
|
copyright and certain other rights. Our licenses are
|
||||||
|
irrevocable. Licensors should read and understand the terms
|
||||||
|
and conditions of the license they choose before applying it.
|
||||||
|
Licensors should also secure all rights necessary before
|
||||||
|
applying our licenses so that the public can reuse the
|
||||||
|
material as expected. Licensors should clearly mark any
|
||||||
|
material not subject to the license. This includes other CC-
|
||||||
|
licensed material, or material used under an exception or
|
||||||
|
limitation to copyright. More considerations for licensors:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensors
|
||||||
|
|
||||||
|
Considerations for the public: By using one of our public
|
||||||
|
licenses, a licensor grants the public permission to use the
|
||||||
|
licensed material under specified terms and conditions. If
|
||||||
|
the licensor's permission is not necessary for any reason--for
|
||||||
|
example, because of any applicable exception or limitation to
|
||||||
|
copyright--then that use is not regulated by the license. Our
|
||||||
|
licenses grant only permissions under copyright and certain
|
||||||
|
other rights that a licensor has authority to grant. Use of
|
||||||
|
the licensed material may still be restricted for other
|
||||||
|
reasons, including because others have copyright or other
|
||||||
|
rights in the material. A licensor may make special requests,
|
||||||
|
such as asking that all changes be marked or described.
|
||||||
|
Although not required by our licenses, you are encouraged to
|
||||||
|
respect those requests where reasonable. More_considerations
|
||||||
|
for the public:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensees
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Attribution 4.0 International Public License
|
||||||
|
|
||||||
|
By exercising the Licensed Rights (defined below), You accept and agree
|
||||||
|
to be bound by the terms and conditions of this Creative Commons
|
||||||
|
Attribution 4.0 International Public License ("Public License"). To the
|
||||||
|
extent this Public License may be interpreted as a contract, You are
|
||||||
|
granted the Licensed Rights in consideration of Your acceptance of
|
||||||
|
these terms and conditions, and the Licensor grants You such rights in
|
||||||
|
consideration of benefits the Licensor receives from making the
|
||||||
|
Licensed Material available under these terms and conditions.
|
||||||
|
|
||||||
|
|
||||||
|
Section 1 -- Definitions.
|
||||||
|
|
||||||
|
a. Adapted Material means material subject to Copyright and Similar
|
||||||
|
Rights that is derived from or based upon the Licensed Material
|
||||||
|
and in which the Licensed Material is translated, altered,
|
||||||
|
arranged, transformed, or otherwise modified in a manner requiring
|
||||||
|
permission under the Copyright and Similar Rights held by the
|
||||||
|
Licensor. For purposes of this Public License, where the Licensed
|
||||||
|
Material is a musical work, performance, or sound recording,
|
||||||
|
Adapted Material is always produced where the Licensed Material is
|
||||||
|
synched in timed relation with a moving image.
|
||||||
|
|
||||||
|
b. Adapter's License means the license You apply to Your Copyright
|
||||||
|
and Similar Rights in Your contributions to Adapted Material in
|
||||||
|
accordance with the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||||
|
closely related to copyright including, without limitation,
|
||||||
|
performance, broadcast, sound recording, and Sui Generis Database
|
||||||
|
Rights, without regard to how the rights are labeled or
|
||||||
|
categorized. For purposes of this Public License, the rights
|
||||||
|
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||||
|
Rights.
|
||||||
|
|
||||||
|
d. Effective Technological Measures means those measures that, in the
|
||||||
|
absence of proper authority, may not be circumvented under laws
|
||||||
|
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||||
|
Treaty adopted on December 20, 1996, and/or similar international
|
||||||
|
agreements.
|
||||||
|
|
||||||
|
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||||
|
any other exception or limitation to Copyright and Similar Rights
|
||||||
|
that applies to Your use of the Licensed Material.
|
||||||
|
|
||||||
|
f. Licensed Material means the artistic or literary work, database,
|
||||||
|
or other material to which the Licensor applied this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
g. Licensed Rights means the rights granted to You subject to the
|
||||||
|
terms and conditions of this Public License, which are limited to
|
||||||
|
all Copyright and Similar Rights that apply to Your use of the
|
||||||
|
Licensed Material and that the Licensor has authority to license.
|
||||||
|
|
||||||
|
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||||
|
under this Public License.
|
||||||
|
|
||||||
|
i. Share means to provide material to the public by any means or
|
||||||
|
process that requires permission under the Licensed Rights, such
|
||||||
|
as reproduction, public display, public performance, distribution,
|
||||||
|
dissemination, communication, or importation, and to make material
|
||||||
|
available to the public including in ways that members of the
|
||||||
|
public may access the material from a place and at a time
|
||||||
|
individually chosen by them.
|
||||||
|
|
||||||
|
j. Sui Generis Database Rights means rights other than copyright
|
||||||
|
resulting from Directive 96/9/EC of the European Parliament and of
|
||||||
|
the Council of 11 March 1996 on the legal protection of databases,
|
||||||
|
as amended and/or succeeded, as well as other essentially
|
||||||
|
equivalent rights anywhere in the world.
|
||||||
|
|
||||||
|
k. You means the individual or entity exercising the Licensed Rights
|
||||||
|
under this Public License. Your has a corresponding meaning.
|
||||||
|
|
||||||
|
|
||||||
|
Section 2 -- Scope.
|
||||||
|
|
||||||
|
a. License grant.
|
||||||
|
|
||||||
|
1. Subject to the terms and conditions of this Public License,
|
||||||
|
the Licensor hereby grants You a worldwide, royalty-free,
|
||||||
|
non-sublicensable, non-exclusive, irrevocable license to
|
||||||
|
exercise the Licensed Rights in the Licensed Material to:
|
||||||
|
|
||||||
|
a. reproduce and Share the Licensed Material, in whole or
|
||||||
|
in part; and
|
||||||
|
|
||||||
|
b. produce, reproduce, and Share Adapted Material.
|
||||||
|
|
||||||
|
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||||
|
Exceptions and Limitations apply to Your use, this Public
|
||||||
|
License does not apply, and You do not need to comply with
|
||||||
|
its terms and conditions.
|
||||||
|
|
||||||
|
3. Term. The term of this Public License is specified in Section
|
||||||
|
6(a).
|
||||||
|
|
||||||
|
4. Media and formats; technical modifications allowed. The
|
||||||
|
Licensor authorizes You to exercise the Licensed Rights in
|
||||||
|
all media and formats whether now known or hereafter created,
|
||||||
|
and to make technical modifications necessary to do so. The
|
||||||
|
Licensor waives and/or agrees not to assert any right or
|
||||||
|
authority to forbid You from making technical modifications
|
||||||
|
necessary to exercise the Licensed Rights, including
|
||||||
|
technical modifications necessary to circumvent Effective
|
||||||
|
Technological Measures. For purposes of this Public License,
|
||||||
|
simply making modifications authorized by this Section 2(a)
|
||||||
|
(4) never produces Adapted Material.
|
||||||
|
|
||||||
|
5. Downstream recipients.
|
||||||
|
|
||||||
|
a. Offer from the Licensor -- Licensed Material. Every
|
||||||
|
recipient of the Licensed Material automatically
|
||||||
|
receives an offer from the Licensor to exercise the
|
||||||
|
Licensed Rights under the terms and conditions of this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
b. No downstream restrictions. You may not offer or impose
|
||||||
|
any additional or different terms or conditions on, or
|
||||||
|
apply any Effective Technological Measures to, the
|
||||||
|
Licensed Material if doing so restricts exercise of the
|
||||||
|
Licensed Rights by any recipient of the Licensed
|
||||||
|
Material.
|
||||||
|
|
||||||
|
6. No endorsement. Nothing in this Public License constitutes or
|
||||||
|
may be construed as permission to assert or imply that You
|
||||||
|
are, or that Your use of the Licensed Material is, connected
|
||||||
|
with, or sponsored, endorsed, or granted official status by,
|
||||||
|
the Licensor or others designated to receive attribution as
|
||||||
|
provided in Section 3(a)(1)(A)(i).
|
||||||
|
|
||||||
|
b. Other rights.
|
||||||
|
|
||||||
|
1. Moral rights, such as the right of integrity, are not
|
||||||
|
licensed under this Public License, nor are publicity,
|
||||||
|
privacy, and/or other similar personality rights; however, to
|
||||||
|
the extent possible, the Licensor waives and/or agrees not to
|
||||||
|
assert any such rights held by the Licensor to the limited
|
||||||
|
extent necessary to allow You to exercise the Licensed
|
||||||
|
Rights, but not otherwise.
|
||||||
|
|
||||||
|
2. Patent and trademark rights are not licensed under this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
3. To the extent possible, the Licensor waives any right to
|
||||||
|
collect royalties from You for the exercise of the Licensed
|
||||||
|
Rights, whether directly or through a collecting society
|
||||||
|
under any voluntary or waivable statutory or compulsory
|
||||||
|
licensing scheme. In all other cases the Licensor expressly
|
||||||
|
reserves any right to collect such royalties.
|
||||||
|
|
||||||
|
|
||||||
|
Section 3 -- License Conditions.
|
||||||
|
|
||||||
|
Your exercise of the Licensed Rights is expressly made subject to the
|
||||||
|
following conditions.
|
||||||
|
|
||||||
|
a. Attribution.
|
||||||
|
|
||||||
|
1. If You Share the Licensed Material (including in modified
|
||||||
|
form), You must:
|
||||||
|
|
||||||
|
a. retain the following if it is supplied by the Licensor
|
||||||
|
with the Licensed Material:
|
||||||
|
|
||||||
|
i. identification of the creator(s) of the Licensed
|
||||||
|
Material and any others designated to receive
|
||||||
|
attribution, in any reasonable manner requested by
|
||||||
|
the Licensor (including by pseudonym if
|
||||||
|
designated);
|
||||||
|
|
||||||
|
ii. a copyright notice;
|
||||||
|
|
||||||
|
iii. a notice that refers to this Public License;
|
||||||
|
|
||||||
|
iv. a notice that refers to the disclaimer of
|
||||||
|
warranties;
|
||||||
|
|
||||||
|
v. a URI or hyperlink to the Licensed Material to the
|
||||||
|
extent reasonably practicable;
|
||||||
|
|
||||||
|
b. indicate if You modified the Licensed Material and
|
||||||
|
retain an indication of any previous modifications; and
|
||||||
|
|
||||||
|
c. indicate the Licensed Material is licensed under this
|
||||||
|
Public License, and include the text of, or the URI or
|
||||||
|
hyperlink to, this Public License.
|
||||||
|
|
||||||
|
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||||
|
reasonable manner based on the medium, means, and context in
|
||||||
|
which You Share the Licensed Material. For example, it may be
|
||||||
|
reasonable to satisfy the conditions by providing a URI or
|
||||||
|
hyperlink to a resource that includes the required
|
||||||
|
information.
|
||||||
|
|
||||||
|
3. If requested by the Licensor, You must remove any of the
|
||||||
|
information required by Section 3(a)(1)(A) to the extent
|
||||||
|
reasonably practicable.
|
||||||
|
|
||||||
|
4. If You Share Adapted Material You produce, the Adapter's
|
||||||
|
License You apply must not prevent recipients of the Adapted
|
||||||
|
Material from complying with this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 4 -- Sui Generis Database Rights.
|
||||||
|
|
||||||
|
Where the Licensed Rights include Sui Generis Database Rights that
|
||||||
|
apply to Your use of the Licensed Material:
|
||||||
|
|
||||||
|
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||||
|
to extract, reuse, reproduce, and Share all or a substantial
|
||||||
|
portion of the contents of the database;
|
||||||
|
|
||||||
|
b. if You include all or a substantial portion of the database
|
||||||
|
contents in a database in which You have Sui Generis Database
|
||||||
|
Rights, then the database in which You have Sui Generis Database
|
||||||
|
Rights (but not its individual contents) is Adapted Material; and
|
||||||
|
|
||||||
|
c. You must comply with the conditions in Section 3(a) if You Share
|
||||||
|
all or a substantial portion of the contents of the database.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 4 supplements and does not
|
||||||
|
replace Your obligations under this Public License where the Licensed
|
||||||
|
Rights include other Copyright and Similar Rights.
|
||||||
|
|
||||||
|
|
||||||
|
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||||
|
|
||||||
|
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||||
|
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||||
|
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||||
|
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||||
|
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||||
|
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||||
|
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||||
|
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||||
|
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||||
|
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||||
|
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||||
|
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||||
|
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||||
|
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||||
|
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
c. The disclaimer of warranties and limitation of liability provided
|
||||||
|
above shall be interpreted in a manner that, to the extent
|
||||||
|
possible, most closely approximates an absolute disclaimer and
|
||||||
|
waiver of all liability.
|
||||||
|
|
||||||
|
|
||||||
|
Section 6 -- Term and Termination.
|
||||||
|
|
||||||
|
a. This Public License applies for the term of the Copyright and
|
||||||
|
Similar Rights licensed here. However, if You fail to comply with
|
||||||
|
this Public License, then Your rights under this Public License
|
||||||
|
terminate automatically.
|
||||||
|
|
||||||
|
b. Where Your right to use the Licensed Material has terminated under
|
||||||
|
Section 6(a), it reinstates:
|
||||||
|
|
||||||
|
1. automatically as of the date the violation is cured, provided
|
||||||
|
it is cured within 30 days of Your discovery of the
|
||||||
|
violation; or
|
||||||
|
|
||||||
|
2. upon express reinstatement by the Licensor.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||||
|
right the Licensor may have to seek remedies for Your violations
|
||||||
|
of this Public License.
|
||||||
|
|
||||||
|
c. For the avoidance of doubt, the Licensor may also offer the
|
||||||
|
Licensed Material under separate terms or conditions or stop
|
||||||
|
distributing the Licensed Material at any time; however, doing so
|
||||||
|
will not terminate this Public License.
|
||||||
|
|
||||||
|
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 7 -- Other Terms and Conditions.
|
||||||
|
|
||||||
|
a. The Licensor shall not be bound by any additional or different
|
||||||
|
terms or conditions communicated by You unless expressly agreed.
|
||||||
|
|
||||||
|
b. Any arrangements, understandings, or agreements regarding the
|
||||||
|
Licensed Material not stated herein are separate from and
|
||||||
|
independent of the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 8 -- Interpretation.
|
||||||
|
|
||||||
|
a. For the avoidance of doubt, this Public License does not, and
|
||||||
|
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||||
|
conditions on any use of the Licensed Material that could lawfully
|
||||||
|
be made without permission under this Public License.
|
||||||
|
|
||||||
|
b. To the extent possible, if any provision of this Public License is
|
||||||
|
deemed unenforceable, it shall be automatically reformed to the
|
||||||
|
minimum extent necessary to make it enforceable. If the provision
|
||||||
|
cannot be reformed, it shall be severed from this Public License
|
||||||
|
without affecting the enforceability of the remaining terms and
|
||||||
|
conditions.
|
||||||
|
|
||||||
|
c. No term or condition of this Public License will be waived and no
|
||||||
|
failure to comply consented to unless expressly agreed to by the
|
||||||
|
Licensor.
|
||||||
|
|
||||||
|
d. Nothing in this Public License constitutes or may be interpreted
|
||||||
|
as a limitation upon, or waiver of, any privileges and immunities
|
||||||
|
that apply to the Licensor or You, including from the legal
|
||||||
|
processes of any jurisdiction or authority.
|
||||||
|
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons is not a party to its public
|
||||||
|
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||||
|
its public licenses to material it publishes and in those instances
|
||||||
|
will be considered the "Licensor." The text of the Creative Commons
|
||||||
|
public licenses is dedicated to the public domain under the CC0 Public
|
||||||
|
Domain Dedication. Except for the limited purpose of indicating that
|
||||||
|
material is shared under a Creative Commons public license or as
|
||||||
|
otherwise permitted by the Creative Commons policies published at
|
||||||
|
creativecommons.org/policies, Creative Commons does not authorize the
|
||||||
|
use of the trademark "Creative Commons" or any other trademark or logo
|
||||||
|
of Creative Commons without its prior written consent including,
|
||||||
|
without limitation, in connection with any unauthorized modifications
|
||||||
|
to any of its public licenses or any other arrangements,
|
||||||
|
understandings, or agreements concerning use of licensed material. For
|
||||||
|
the avoidance of doubt, this paragraph does not form part of the
|
||||||
|
public licenses.
|
||||||
|
|
||||||
|
Creative Commons may be contacted at creativecommons.org.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Git Logo by [Jason Long](https://bsky.app/profile/jasonlong.me) is licensed under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/).
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M6 5C6 3.89543 6.89543 3 8 3C9.10457 3 10 3.89543 10 5C10 6.10457 9.10457 7 8 7C6.89543 7 6 6.10457 6 5ZM5.49998 8L10.5 8C11.3284 8 12 8.67157 12 9.5C12 10.6161 11.541 11.5103 10.7879 12.1148C10.0466 12.7098 9.05308 13 8 13C6.94692 13 5.95342 12.7098 5.21215 12.1148C4.45897 11.5103 4 10.6161 4 9.5C4 8.67161 4.67156 8 5.49998 8ZM8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0ZM1 8C1 4.13401 4.13401 1 8 1C11.866 1 15 4.13401 15 8C15 11.866 11.866 15 8 15C4.13401 15 1 11.866 1 8Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 660 B |