Compare commits

...

19 Commits

Author SHA1 Message Date
7d61aadc5d Актуализация и мелочи
Some checks failed
Build images / build (push) Failing after 13m56s
2026-01-02 23:46:04 +08:00
c1af326438 Мелочь про актуальность
All checks were successful
Build images / build (push) Successful in 1m56s
2025-12-26 23:24:00 +08:00
ba6b948d24 Корректировки о статусной странице
All checks were successful
Build images / build (push) Successful in 3m11s
2025-11-30 18:40:12 +08:00
db7ac03265 Описание статусной страницы
All checks were successful
Build images / build (push) Successful in 1m33s
2025-11-30 10:57:07 +08:00
fd11792a24 Обновлены скриншоты о странице плейлиста + мелочи 2025-11-30 10:35:10 +08:00
dcf1fc909c Фикс сломанных ссылок
All checks were successful
Build images / build (push) Successful in 1m42s
2025-11-30 00:20:29 +08:00
dc05ceb780 Мелочи по правообладателям 2025-11-30 00:18:26 +08:00
7cbb906258 Мелочи по FAQ 2025-11-30 00:18:08 +08:00
e62e555a3f Уточнения о статусах плейлистов и каналов 2025-11-29 23:59:50 +08:00
7b556a48af Скорректирована страница о ТГ-чате 2025-11-29 23:38:51 +08:00
710759c22d Скорректирована страница поддержки 2025-11-29 23:38:24 +08:00
d67059d1ec Обновлена страница про статусы плейлистов 2025-11-29 22:45:45 +08:00
ba5efb5be8 Обновлена страница про отбор плейлистов 2025-11-29 22:44:59 +08:00
0d60dee8d0 Обновлены скриншоты главной страницы 2025-11-29 22:41:50 +08:00
0fee02a486 Добавлена страница для правообладателей 2025-11-23 21:53:05 +08:00
4976b9c85a Описаны новые аргументы iptvc check --repeat/--every
All checks were successful
Build images / build (push) Successful in 1m37s
2025-11-23 01:36:58 +08:00
6d460f4263 Пайплайн сборки контейнера с готовой документацией
All checks were successful
Build images / build (push) Successful in 2m2s
2025-11-22 22:34:15 +08:00
1d24b3fab5 Мелкие уточнения 2025-11-22 22:33:06 +08:00
88586d15a2 Мелкие доработки Makefile 2025-11-22 22:32:37 +08:00
30 changed files with 347 additions and 140 deletions

View File

@@ -0,0 +1,44 @@
# https://docs.gitea.com/usage/actions/overview
# https://docs.github.com/ru/actions/reference/workflows-and-actions/contexts
name: Build images
on:
push:
branches:
- 'master'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with: # https://github.com/actions/checkout
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with: # https://github.com/docker/setup-buildx-action
buildkitd-config-inline: |
# https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md
[ registry."docker.io" ]
mirrors = ["https://dockerhub.timeweb.cloud", "https://dh-mirror.gitverse.ru"]
http = true
insecure = true
- name: Log in to Gitea Container Registry
uses: docker/login-action@v3
with: # https://github.com/docker/login-action
registry: git.axenov.dev
username: ${{ secrets.USERNAME }}
password: ${{ secrets.RELEASE_TOKEN }}
- name: Build and push Docker images
uses: docker/build-push-action@v5
with: # https://github.com/docker/build-push-action
context: .
push: true
tags: |
git.axenov.dev/iptv/m3u-su-docs:${{ github.ref_name }}
git.axenov.dev/iptv/m3u-su-docs:latest

View File

@@ -1,10 +1,10 @@
FROM squidfunk/mkdocs-material AS m3u-su-docs-builder FROM squidfunk/mkdocs-material AS builder
COPY . /docs COPY . /docs
RUN mkdocs build RUN mkdocs build
FROM nginx:alpine AS m3u-su-docs FROM nginx:alpine AS iptv-docs
LABEL org.opencontainers.image.authors="Anthony Axenov <anthonyaxenov@gmail.com>" LABEL org.opencontainers.image.authors="Anthony Axenov <anthonyaxenov@gmail.com>"
COPY --from=m3u-su-docs-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
EXPOSE 80 EXPOSE 80

View File

@@ -1,4 +1,4 @@
## image: Run mkdocs with live-reloading ## image: Run mkdocs with live-reloading (localhost:3000)
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:3000 to see live preview"
@docker run \ @docker run \
@@ -6,34 +6,42 @@ live:
--rm \ --rm \
--interactive \ --interactive \
--tty \ --tty \
-p 3000:8000 \ --publish 3000:8000 \
-v ${PWD}:/docs \ --volume ${PWD}:/docs \
--name iptv-docs-dev \
squidfunk/mkdocs-material:9.6.20 squidfunk/mkdocs-material:9.6.20
## image: Build local static site ## image: Build local static site
build: site:
@echo "Wait until mkdocs finish"
@docker run \ @docker run \
--pull always \ --pull always \
--rm \ --rm \
--interactive \ --interactive \
--tty \ --tty \
-v ${PWD}:/docs \ --volume ${PWD}:/docs \
--name iptv-docs-dev \
squidfunk/mkdocs-material:9.6.20 build squidfunk/mkdocs-material:9.6.20 build
## image: Build docker image ## image: Build docker image
image: image:
@docker build \ @docker build \
--tag m3u-su-docs:latest \ --tag iptv-docs:latest \
--tag git.axenov.dev/iptv/m3u-su-docs:latest \ --tag git.axenov.dev/iptv/iptv-docs:latest \
. .
## push: Push docker image to registry ## push: Push docker image to registry
push: push:
@docker push git.axenov.dev/iptv/m3u-su-docs:latest @docker push git.axenov.dev/iptv/iptv-docs:latest
## push: Push docker image to registry ## run: Run docker image (localhost:3001)
run: run:
@docker run -p 3001:80 git.axenov.dev/iptv/m3u-su-docs:latest @echo "Wait until container starts and open http://localhost:3001 to see ready static website"
@docker run \
--rm \
--publish 3001:80 \
--name iptv-docs \
git.axenov.dev/iptv/iptv-docs:latest
## help: Show this message and exit ## help: Show this message and exit
help: Makefile help: Makefile

View File

@@ -105,6 +105,7 @@ nav:
- index.md - index.md
- docs.md - docs.md
- support.md - support.md
- legal.md
- 'Общая информация': - 'Общая информация':
- common/index.md - common/index.md
- common/how-it-works.md - common/how-it-works.md
@@ -124,6 +125,7 @@ nav:
- iptvc/commands/help.md - iptvc/commands/help.md
- iptvc/commands/check.md - iptvc/commands/check.md
- iptvc/commands/version.md - iptvc/commands/version.md
- statuspage.md
- 'Для разработчиков': - 'Для разработчиков':
- dev/index.md - dev/index.md
- dev/local-dev.md - dev/local-dev.md

View File

@@ -1,3 +1,49 @@
:root {
/* Yoomoney logo */
--md-admonition-icon--yoomoney: url('data:image/svg+xml;charset=utf-8,<svg width="169" height="120" viewBox="0 0 169 120" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M108.99 0C75.5725 0 48.9902 26.962 48.9902 60C48.9902 93.4177 75.9523 120 108.99 120C142.028 120 168.99 93.038 168.99 60C168.99 26.962 142.028 0 108.99 0ZM108.99 82.4051C96.8383 82.4051 86.5852 72.1519 86.5852 60C86.5852 47.8481 96.8383 37.5949 108.99 37.5949C121.142 37.5949 131.395 47.8481 131.395 60C131.016 72.1519 121.142 82.4051 108.99 82.4051Z" fill="white"/><path d="M48.6076 17.4684V104.81H27.3418L0 17.4684H48.6076V17.4684Z" fill="white"/></svg>');
/* Boosty logo */
--md-admonition-icon--boosty: url('data:image/svg+xml;charset=utf-8,<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2.661 14.337 6.801 0h6.362L11.88 4.444l-0.038 0.077 -3.378 11.733h3.15c-1.321 3.289 -2.35 5.867 -3.086 7.733 -5.816 -0.063 -7.442 -4.228 -6.02 -9.155M8.554 24l7.67 -11.035h-3.25l2.83 -7.073c4.852 0.508 7.137 4.33 5.791 8.952C20.16 19.81 14.344 24 8.68 24h-0.127z" fill="white" stroke-width="1"></path></svg>');
}
/* Yoomoney styling */
.md-typeset .admonition.yoomoney,
.md-typeset details.yoomoney {
border-color: rgba(113, 47, 244, 1);
}
.md-typeset .yoomoney > .admonition-title,
.md-typeset .yoomoney > summary {
background-color: rgba(113, 47, 244, 0.1);
}
.md-typeset .yoomoney > .admonition-title::before,
.md-typeset .yoomoney > summary::before {
background-color: rgb(113, 47, 244);
-webkit-mask-image: var(--md-admonition-icon--yoomoney);
mask-image: var(--md-admonition-icon--yoomoney);
}
/* Boosty styling */
.md-typeset .admonition.boosty,
.md-typeset details.boosty {
border-color: rgb(241, 95, 44);
}
.md-typeset .boosty > .admonition-title,
.md-typeset .boosty > summary {
background-color: rgba(241, 95, 44, 0.1);
}
.md-typeset .boosty > .admonition-title::before,
.md-typeset .boosty > summary::before {
background-color: rgb(241, 95, 44);
-webkit-mask-image: var(--md-admonition-icon--boosty);
mask-image: var(--md-admonition-icon--boosty);
}
.chapter li.part-title { .chapter li.part-title {
font-size: 1.2em; font-size: 1.2em;
} }
@@ -14,7 +60,8 @@ main ol li {
box-sizing: border-box; box-sizing: border-box;
color: rgb(33, 37, 41); color: rgb(33, 37, 41);
display: inline-block; display: inline-block;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 10.5px; font-size: 10.5px;
font-weight: 700; font-weight: 700;
height: 17.8438px; height: 17.8438px;
@@ -36,6 +83,11 @@ main ol li {
background-color: rgb(25, 135, 84); background-color: rgb(25, 135, 84);
} }
.badge.online-percent {
border: 1px solid rgb(25, 135, 84);
color: var(--md-typeset-color);
}
.badge.offline { .badge.offline {
background-color: rgb(220, 53, 69); background-color: rgb(220, 53, 69);
} }
@@ -45,7 +97,11 @@ main ol li {
} }
.badge.adult { .badge.adult {
background-color: rgb(255, 193, 7) background-color: rgb(255, 193, 7);
}
.badge.lapka {
background-color: rgb(13, 202, 240);
} }
.icon.online { .icon.online {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -3,78 +3,91 @@ icon: material/file-refresh-outline
tags: ["статусы", "плейлисты", "каналы", "iptvc"] tags: ["статусы", "плейлисты", "каналы", "iptvc"]
--- ---
# :material-file-refresh-outline: Как проверяются плейлисты # :material-file-refresh-outline: Проверки и статусы
Плейлисты проверяются автоматически с некоей периодичностью при помощи [iptvc](../iptvc/index.md).
Она может настраиваться мной в разное время, чтобы сбалансировать нагрузку на сервер.
!!! danger "Я не гарантирую корректность и актуальность плейлистов, которые ты увидишь на сайте, как и корректность результатов их проверки." !!! danger "Я не гарантирую корректность и актуальность плейлистов, которые ты увидишь на сайте, как и корректность результатов их проверки."
После прочтения этой страницы ты поймёшь почему. После прочтения этой страницы ты поймёшь почему.
Плейлисты [проверяются автоматически](../iptvc/index.md) с некоей периодичностью.
Хотя я и стараюсь улучшать качество проверок, но всё же рекомендую проверять желаемые плейлисты самостоятельно вручную, ибо нет никаких гарантий: Хотя я и стараюсь улучшать качество проверок, но всё же рекомендую проверять желаемые плейлисты самостоятельно вручную, ибо нет никаких гарантий:
* что плейлист (не) работоспособен * что плейлист составлен корректно и обработается правильно;
* он может быть и рабочий, но проверка может не сработать из-за таймаута запроса; * что плейлист (не) работоспособен:
* он уже может быть и нерабочим, но результаты последней проверки показывают обратное; * он может работать, но проверка заврешена из-за какой-то технической ошибки;
* что плейлист корректно обработается (будут правильно определён список каналов, их названия, атрибуты и пр.); * он уже может не работать, но результаты последней проверки показывают обратное;
* что транслируемый контент соответствует названиям каналов; * что транслируемый контент соответствует заявленным названиям;
* что сейчас или через X времени там не окажется [заглушка](../faq.md#заглушка). * что сейчас или через X времени там не окажется [заглушка](../faq.md#заглушка).
<a id="плейлисты"></a> <a id="playlists"></a>
## Плейлисты ## Статусы плейлистов
Каждый плейлист может быть в одном из трёх статусов: Каждый плейлист может быть в одном из трёх статусов:
* <span class="badge unknown">unknown</span> — Плейлист в очереди на проверку * <span class="badge unknown">unknown</span>**Плейлист в очереди на проверку**
Он сменит свой статус в ближайшие минуты. Он сменит свой статус в ближайшие минуты.
* <span class="badge online">online</span> — Плейлист активен * <span class="badge online">online</span>**Плейлист проверен**
Это не значит, что он работает. Это не значит, что он работает.
Это значит, что адрес плейлиста корректен и там, *вероятно*, *что-то* транслируется. Это значит, что адрес плейлиста корректен и *вероятно* там *что-то* транслируется.
В нём может быть 0 каналов — значит, содержимое потёрли.
* <span class="badge offline">offline</span> — Плейлист недоступен * <span class="badge offline">offline</span>**Плейлист недоступен**
Если этот статус висит постоянно, значит это главный кандидат на удаление из проекта. Либо плейлист удалён с сервера, где он располагался когда-то, либо это просто разовый сбой (например, таймаут проверки).
Но это может быть просто разовый сбой (например, таймаут проверки), и, *возможно*, скоро он станет доступен. *Возможно*, (не) скоро он (не) станет доступен.
!!! info "Обрати внимание" !!! info "Обрати внимание"
Независимо от статуса плейлиста на сайте, его можно добавить в свой плеер по "Ссылке для ТВ" и проверить самостоятельно. Независимо от статуса плейлиста на сайте, его можно добавить в свой плеер по "Ссылке для ТВ" и проверить самостоятельно.
Проверка плейлиста не влияет на его работоспособность. Проверка плейлиста не влияет на его работоспособность.
<a id="каналы"></a> <a id="extra"></a>
## Каналы ### Дополнительные возможности
Каждый канал в любом плейлисте может быть в одном из трёх статусов: Если плейлист <span class="badge online">online</span> (успешно проверен), то у него могут быть дополнительные значки:
* <span class="icon online"><ion-icon name="radio-button-on-outline"></ion-icon></span>*Возможно*, канал работает
Но там может транслироваться какая-нибудь [заглушка](../faq.md#заглушка) (например, от [Wink](../faq.md#wink)).
* <span class="icon offline"><ion-icon name="radio-button-on-outline"></ion-icon></span>*Возможно*, канал не работает
Чем больше таких каналов в плейлисте, тем сложнее будет листать плейлист в плеере или на ТВ.
Но, *возможно*, *когда-нибудь* плейлист обновят и канал будет работать исправно.
Также и здесь может быть просто разовый сбой (например, таймаут проверки), и (возможно) скоро он станет доступен.
!!! info "Обрати внимание"
Пропорции рабочих и нерабочих каналов в плейлистах может и будет меняться от проверки к проверке.
Это нормально, таковы технические особенности проверки.
<a id="возможности"></a>
## Возможности
В описаниях плейлистов, которые находятся в статусе <span class="badge online">online</span>, можно встретить следующие иконки:
* <span class="badge online-percent">95%</span> — количество рабочих каналов на момент проверки;
* <span class="badge adult">18+</span> — плейлист имеет каналы для взрослых;
* <span class="badge lapka"><ion-icon name="paw"></ion-icon></span> — плейлист может быть нестабилен
Это значит, что в нём есть каналы со специальными параметрами: токенами, логинами и паролями, которые рано или поздно истекут или будут заблокированы (если ещё не).
Также это признак бесплатного пробного периода.
* <ion-icon name="folder-open-outline"></ion-icon> — каналы плейлиста разбиты на группы (например, музыкальные каналы и региональные); * <ion-icon name="folder-open-outline"></ion-icon> — каналы плейлиста разбиты на группы (например, музыкальные каналы и региональные);
* <ion-icon name="newspaper-outline"></ion-icon> — плейлист предоставляет программу передач для каналов; * <ion-icon name="newspaper-outline"></ion-icon> — плейлист предоставляет программу передач для каналов;
* <ion-icon name="play-back"></ion-icon> — плейлист предоставляет возможность перемотки передач. * <ion-icon name="play-back"></ion-icon> — плейлист предоставляет возможность перемотки передач.
Если плейлист недоступен или непроверен, этих иконок не будет. Если плейлист <span class="badge unknown">unknown</span> или <span class="badge offline">offline</span>, этих иконок не будет.
<a id="для-взрослых"></a> !!! info "Обрати внимание"
1. Пропорции рабочих и нерабочих каналов в плейлистах могут меняться от проверки к проверке.
Это нормально, таковы технические особенности проверки.
2. Работа архива и программы передач зависит от выбранного [плеера](players.md).
Некоторые это просто не поддерживают.
<a id="channels"></a>
## Статусы каналов
Каждый канал в любом плейлисте может быть в одном из трёх статусов:
* <span class="icon online"><ion-icon name="radio-button-on-outline"></ion-icon></span>***Возможно*, канал работает**
Но там может транслироваться какая-нибудь [заглушка](../faq.md#заглушка) (например, от [Wink](../faq.md#wink)) или другой канал.
* <span class="icon offline"><ion-icon name="radio-button-on-outline"></ion-icon></span>***Возможно*, канал не работает**
Чем больше таких каналов в плейлисте, тем сложнее будет листать плейлист в плеере или на ТВ.
Но *возможно когда-нибудь* плейлист обновят и канал будет работать исправно.
Также здесь может быть просто разовый сбой (например, таймаут проверки).
* <span class="badge lapka"><ion-icon name="paw"></ion-icon></span>**Канал может быть нестабилен**
Это значит, что для него указаны специальные параметры: токен, логин или пароль, которые рано или поздно истекут или будут заблокированы.
Тогда канал перестанет работать.
Также это признак бесплатного пробного периода.
* <span class="badge adult">18+</span>**Канал для взрослых**
Читай ниже.
<a id="adult"></a>
## Контент для взрослых ## Контент для взрослых
Это откровенно порнографический, эротический или другой контент, неприемлемый для детской психики (например, жанровые каналы с фильмами ужасов). Это откровенно порнографический, эротический или другой контент, неприемлемый для детской психики (например, жанровые каналы с фильмами ужасов).
Если при проверке плейлиста обнаружен хотя бы один канал для взрослых, то сам канал и весь плейлист помечается значком <span class="badge adult">18+</span> Если при проверке плейлиста обнаружен хотя бы один канал для взрослых, то этот канал и весь плейлист помечается значком <span class="badge adult">18+</span>.
Такие каналы определяются благодаря правилам, описанным в файле [channels.json](../formats/channels.md). Такие каналы определяются благодаря правилам, описанным в файле [channels.json](../formats/channels.md).
Они применяются к названиям каналов и их атрибутам (`tvg-id`, `tvg-name`), которые описывают канал в плейлисте. Они применяются к названиям каналов и их атрибутам (`tvg-id`, `tvg-name`), которые описывают канал в плейлисте.

View File

@@ -8,7 +8,7 @@ tags: ["плееры", "плейлисты"]
1. Найти какой-нибудь [плеер](./players.md) 1. Найти какой-нибудь [плеер](./players.md)
2. Узнать как в него добавить плейлист по ссылке 2. Узнать как в него добавить плейлист по ссылке
3. Найти желаемый плелист из [списка](./list.md) 3. Найти желаемый плелист из [списка](./list.md)
4. Найти на странице ["Ссылку для ТВ"](details.md#ссылка-для-тв) и ввести (скопировать) её в поле ввода адреса в плеере 4. Найти на странице ["Ссылку для ТВ"](details.md#shortlink) и ввести (скопировать) её в поле ввода адреса в плеере
Для некоторых [плееров](./players.md) уже есть информация как добавить плейлист. Для некоторых [плееров](./players.md) уже есть информация как добавить плейлист.

View File

@@ -59,17 +59,13 @@ tags: ["сайт", "статусы", "каналы"]
## Список каналов ## Список каналов
![Cписок каналов](../assets/img/pls-details/ch-list.jpg)
В заголовке пишется их общее количество. В заголовке пишется их общее количество.
Если общее количество каналов 500 и более, то под заголовком отобразится подсказка, чтобы ты не убегал раньше времени. ![Cписок каналов](../assets/img/pls-details/ch-list.jpg)
Надо просто подождать несколько секунд, список догрузится и подсказка исчезнет.
??? quote "Скриншот подсказки" В списке всегда отображается не более 100 каналов.
!!! success "Да, это недоработка, подпёртая костылём, но это беспокоит меня меньше всего."
Может быть когда-нибудь сделаю лучше. Или нет. Воспользуйтесь поиском, чтобы найти интересующий.
![Скриншот подсказки над списком каналов](../assets/img/pls-details/hint.jpg)
### Поиск каналов ### Поиск каналов
@@ -98,7 +94,7 @@ tags: ["сайт", "статусы", "каналы"]
??? quote "Пример фильтрации" ??? quote "Пример фильтрации"
![Скриншот используемого фильтра списка каналов](../assets/img/pls-details/filter.jpg) ![Скриншот используемого фильтра списка каналов](../assets/img/pls-details/filter.jpg)
<a id="ссылка-для-тв"></a> <a id="shortlink"></a>
## Ссылка для ТВ ## Ссылка для ТВ
Она может быть задана в нескольких форматах. Она может быть задана в нескольких форматах.

View File

@@ -8,7 +8,7 @@ hide: [toc]
<div class="grid cards" markdown> <div class="grid cards" markdown>
- [:material-cogs: Как работает сервис](how-it-works.md) - [:material-cogs: Как работает сервис](how-it-works.md)
- [:material-file-eye-outline: Как отбираются плейлисты](selection.md) - [:material-file-eye-outline: Как отбираются плейлисты](selection.md)
- [:material-file-refresh-outline: Как проверяются плейлисты](checks.md) - [:material-file-refresh-outline: Проверки и статусы](checks.md)
- [:fontawesome-solid-list-check: Список плейлистов](list.md) - [:fontawesome-solid-list-check: Список плейлистов](list.md)
- [:material-table-eye: Страница плейлиста](details.md) - [:material-table-eye: Страница плейлиста](details.md)
- [:material-television-play: Как подключить плейлист](connect.md) - [:material-television-play: Как подключить плейлист](connect.md)

View File

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

View File

@@ -5,11 +5,15 @@ tags: ["статусы", "плейлисты"]
# :material-file-eye-outline: Как отбираются плейлисты # :material-file-eye-outline: Как отбираются плейлисты
Есть некоторые критерии, по которым плейлисты отбираются в проект: Есть некоторые важные критерии, по которым плейлисты отбираются в проект:
* Прежде всего — каналы РФ и бывшего СНГ, но не только они - открытый источник и прямая ссылка;
* Открытый источник - автообновление;
* Прямая ссылка на плейлист - бесплатный доступ, без необходимости регистрации, без пробного периода;
* Автообновление плейлиста - без ограничений, в т. ч. по количеству устройств, плеерам, длительности просмотра;
- безусловная доступность с территории РФ.
В основном, в плейлистах именно трансляции телеканалов, но может быть и просто список каких-то (мульт)фильмов и записи телепередач, находящихся на чужих дисках (как если бы вы сами составили плейлист, например, с музыкой). В основном, в плейлистах именно трансляции телеканалов, но может быть и медиатека: просто список каких-то (мульт)фильмов и записи телепередач, находящихся на чужих дисках (как если бы вы сами составили плейлист, например, с музыкой).
!!! danger "Плейлисты, нарушающие законодательство, удаляются с сайта окончательно по факту обращения от правообладателя."
И претензии на этот счёт не принимаются.

View File

@@ -81,7 +81,7 @@ make live
## Генерация статического сайта ## Генерация статического сайта
``` ```
make build make site
``` ```
Генерирует статические файлы, которую можно версионировать, хранить,деплоить отдельно или просматривать на ПК через браузер. Генерирует статические файлы, которую можно версионировать, хранить,деплоить отдельно или просматривать на ПК через браузер.
@@ -96,7 +96,7 @@ make image
Собирает docker-образ на основе nginx, генерируя перед этим статический сайт. Собирает docker-образ на основе nginx, генерируя перед этим статический сайт.
Запустить контейнер из этого образа можно командой: Запустить контейнер из этого образа по адресу [localhost:3001](http://localhost:3001) можно командой:
``` ```
make run make run

View File

@@ -2,11 +2,10 @@
icon: material/book-open-page-variant-outline icon: material/book-open-page-variant-outline
--- ---
# :material-book-open-page-variant-outline: Работа с документацией # :material-book-open-page-variant-outline: Об этой документации
!!! warning "Актуальность" !!! warning "Актуальность документации может отставать от текущей версии сервиса, его исходных кодов и инфраструктуры"
Она может отставать от актуальной версии сервиса, его исходных кодов и инфраструктуры. Поддерживать содержимое в актуальном состоянии большой труд.
Поддерживать документацию в актуальном состоянии — тоже труд.
Прошу отнестись с пониманием, а лучше — [помочь делом](support.md#participate). Прошу отнестись с пониманием, а лучше — [помочь делом](support.md#participate).
!!! danger "Тем не менее, прошу прочесть её!" !!! danger "Тем не менее, прошу прочесть её!"

View File

@@ -11,38 +11,36 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
## Добавь каналы! ## Добавь каналы!
Нет. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
## Удали каналы! ## Удали каналы!
Нет. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
## Но мне нужны конкретные каналы! ## Но мне нужны конкретные каналы!
Ищи. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
## Сделай мне плейлист! ## Сделай мне плейлист!
Нет. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
## Исправь плейлист! ## Исправь плейлист!
Нет. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
## А за деньги? ## А за деньги?
[Пожертвованиям](support.md) я только рад. Пожалуйста, обратитесь к [этому разделу документации](https://go-friend-go.narod.ru).
Но нет.
## Эти плейлисты бесплатны? ## Эти плейлисты бесплатны?
Возможно. Возможно.
По крайней мере, так утверждают источники, которые их распространяют. По крайней мере, так утверждают источники, которые их распространяют.
Но гарантий никаких никто не даёт. Но гарантий никаких никто не даёт и не может.
Любой плейлист и любой канал в любом плейлисте может сдохнуть навсегда в любой момент. Любой плейлист и любой канал в любом плейлисте может сдохнуть навсегда в любой момент.
Или показывать [заглушку](#заглушка). Или показать [заглушку](#заглушка).
И претензии на этот счёт я не принимаю. И претензии на этот счёт я не принимаю.
@@ -55,21 +53,21 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
Вспоминай. Вспоминай.
## Нет программы передач (EPG) у *канала*, что делать? ## У **канала** нет программы передач (EPG), что делать?
Фига в том, что EPG может быть и [указан](formats/m3u.md#url-tvg) в плейлисте, но у конкретного канала могут быть указаны некорректные [`tvg-id`](formats/m3u.md#tvg-id) или [`tvg-name`](formats/m3u.md#tvg-name). Фига в том, что EPG может быть и [указан](formats/m3u.md#url-tvg) в плейлисте, но у конкретного канала могут быть указаны некорректные [`tvg-id`](formats/m3u.md#tvg-id) или [`tvg-name`](formats/m3u.md#tvg-name).
Может, его дёрнули из другого листа и не подогнали под другую EPG. Может, его дёрнули из другого листа и не подогнали под другую EPG.
Так, что вариантов масса: Так что вариантов масса:
* смотреть как есть; * смотреть как есть;
* найти другой плейлист, где этот канал есть не только сам по себе, но и с телепрограммой; * найти другой плейлист, где этот канал есть с телепрограммой;
* скачать плейлист себе файлом, исправить атрибуты канала и добавить в плеер уже этот лист, но забыть о его автообновлении; * скачать плейлист себе файлом, исправить атрибуты канала и добавить в плеер уже этот лист, но забыть о его автообновлении;
* настроить другую программу передач (см. ниже). * настроить другую программу передач (см. ниже).
Также, помни, что не все плееры вообще поддерживают работу с телепрограммой. Также, помни, что не все плееры вообще поддерживают работу с телепрограммой.
## Нет программы передач (EPG) у *плейлиста*, что делать? ## У **плейлиста** нет программы передач (EPG), что делать?
Помни: Помни:
@@ -117,13 +115,13 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
## Почему на сайте плейлист онлайн, но в нём 0 каналов? ## Почему на сайте плейлист онлайн, но в нём 0 каналов?
[Тебе сюда](common/checks.md#плейлисты). [Тебе сюда](common/checks.md#playlists).
## Почему на сайте плейлист онлайн, но у меня он не работает? ## Почему на сайте плейлист онлайн, но у меня он не работает?
Что значит "не работает"? Что значит "не работает"?
* Ты уверен, что ссылка в [правильном формате](common/details.md#ссылка-для-тв)? * Ты уверен, что ссылка в [правильном формате](common/details.md#shortlink)?
* Ты уверен, что у тебя нормальное интернет-соединение? * Ты уверен, что у тебя нормальное интернет-соединение?
* Плеер показывает какую-то ошибку при добавлении плейлиста? * Плеер показывает какую-то ошибку при добавлении плейлиста?
* Плейлист добавляется по ссылке, но каналы не загружаются или плеер зависает? * Плейлист добавляется по ссылке, но каналы не загружаются или плеер зависает?
@@ -162,7 +160,7 @@ tags: ["сайт", "каналы", "плейлисты", "epg", "плееры",
Да, в плейлистах порнуха. Да, в плейлистах порнуха.
Это [явно помечается](common/checks.md#для-взрослых) везде, где это технически возможно. Это [явно помечается](common/checks.md#adult) везде, где это технически возможно.
Смотри с удовольствием сколько хочешь, всё для тебя. Смотри с удовольствием сколько хочешь, всё для тебя.
Или без удовольствия. Или без удовольствия.

View File

@@ -9,10 +9,11 @@ icon: material/home
!!! info "Все необходимые адреса" !!! info "Все необходимые адреса"
**Веб-сайт:** [m3u.su](https://m3u.su) **Веб-сайт:** [m3u.su](https://m3u.su)
**Документация:** [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)
Новостной канал: [@iptv_aggregator](https://t.me/iptv_aggregator) Telegram-канал: [@iptv_aggregator](https://t.me/iptv_aggregator)
Обсуждение: [@iptv_aggregator_chat](tg/chat.md) Обсуждение: [@iptv_aggregator_chat](https://t.me/iptv_aggregator_chat)
Бот: [@iptv_aggregator_bot](tg/bot.md) Бот: [@iptv_aggregator_bot](https://t.me/iptv_aggregator_bot)
Далеко не все пользователи, желающие использовать цифровое ТВ, могут позволить себе подключение IPTV у своего провайдера или поставщиков контента. Далеко не все пользователи, желающие использовать цифровое ТВ, могут позволить себе подключение IPTV у своего провайдера или поставщиков контента.

View File

@@ -89,7 +89,54 @@ iptvc check -u https://site.com/playlist.m3u8 --url http://other.com/list.m3u
Пример: Пример:
```bash ```bash
iptvc check -c RU_BASIC --code MOVIE_PREMIUM iptvc check -i ~/my.ini -c RU_BASIC --code MOVIE_PREMIUM
```
<a id="repeat"></a>
## `--repeat`
Указывает количество повторений (итераций) команды.
Значение по умолчанию: `1`
Если указано `0`, тогда:
* повторение будет бесконечным;
* если переданы [`--url`](#url), [`--file`](#file) или [`--code`](#code), то на каждой итерации будут проверяться только указанные плейлисты;
* если не переданы [`--url`](#url), [`--file`](#file) или [`--code`](#code), то на каждой итерации список плейлистов будет подготавливаться заново.
Если при этом используется кеширование, то проверенные плейлисты (результаты проверки которых ещё находятся в кеше) проверяться не будут.
Пример:
```bash
# проверить 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
```
<a id="every"></a>
## `--every`
Указывает количество секунд между повторениями (итерациями) команды.
Значение по умолчанию: `5`
Если указано `0`, то задержки не будет.
Пример:
```bash
# проверить 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
``` ```
<a id="random"></a> <a id="random"></a>
@@ -97,8 +144,6 @@ iptvc check -c RU_BASIC --code MOVIE_PREMIUM
Указывает максимальное количество случайных плейлистов из ini-файла для проверки. Указывает максимальное количество случайных плейлистов из ini-файла для проверки.
Можно указать только однажды.
!!! warning "Работает только вместе с [`--ini`](#ini)." !!! warning "Работает только вместе с [`--ini`](#ini)."
Если не указан ни разу, то будут проверены все плейлисты, которые указаны в ini-файле. Если не указан ни разу, то будут проверены все плейлисты, которые указаны в ini-файле.
@@ -145,7 +190,3 @@ iptvc check -i ~/my.ini -r 10 -q --json
```bash ```bash
iptvc check --random 10 --verbose iptvc check --random 10 --verbose
``` ```

View File

@@ -24,13 +24,13 @@ tags: ["iptvc"]
Тег `latest` всегда соответствует последней версии, он подразумевается по умолчанию: Тег `latest` всегда соответствует последней версии, он подразумевается по умолчанию:
```shell ```shell
docker run --pull always git.axenov.dev/iptv/iptvc КОМАНДА [АРГУМЕНТЫ] docker run --pull always --name iptvc git.axenov.dev/iptv/iptvc КОМАНДА [АРГУМЕНТЫ]
``` ```
Для использования другой версии следует явно указать её: Для использования другой версии следует явно указать её:
```shell ```shell
docker run --pull always git.axenov.dev/iptv/iptvc:v1.0.6 КОМАНДА [АРГУМЕНТЫ] docker run --pull always --name iptvc git.axenov.dev/iptv/iptvc:v1.0.6 КОМАНДА [АРГУМЕНТЫ]
``` ```
## Построение собственного образа ## Построение собственного образа
@@ -51,7 +51,7 @@ GOOS=darwin GOARCH=arm64 ./build-docker-image.sh [<версия>]
Запуск: Запуск:
``` ```
docker run --pull always iptvc:[latest|<версия>] КОМАНДА [АРГУМЕНТЫ] docker run --pull always --name iptvc git.axenov.dev/iptv/iptvc КОМАНДА [АРГУМЕНТЫ]
``` ```
## Использование образа в Docker compose ## Использование образа в Docker compose

20
src/legal.md Normal file
View File

@@ -0,0 +1,20 @@
---
icon: material/wallet-outline
---
# :material-wallet-outline: Правообладателям
Данные, представленные на сайте https://m3u.su, получены автоматически из открыто доступных в интернете IPTV-плейлистов, опубликованных третьими лицами.
При наличии технической возможности, источник плейлиста может быть указан на вкладке [«Основные данные»](common/details.md).
Сервис https://m3u.su не размещает и не транслирует медиаконтент, не создаёт, не призывает использовать и распространять плейлисты третьих лиц, а также не оказывает услуг по ретрансляции телепрограмм.
Подробности о проекте и о том, как здесь оказались объекты ваших прав, читайте на страницах этой документации.
Информация о телеканалах (наименования, логотипы, технический статус и другие сведения) формируется исключительно путём обработки содержимого самого плейлиста.
Вся информация носит технический и ознакомительный характер, и её достоверность не гарантируется.
Все права на торговые марки и графические изображения принадлежат их законным владельцам.
Если вы являетесь правообладателем и считаете, что сведения на этой странице затрагивают ваши права, вы можете направить конфиденциальное уведомление на адрес **<abuse@m3u.su>**.
Плейлисты, нарушающие законодательство, удаляются с сайта окончательно по факту обращения от правообладателя.

29
src/statuspage.md Normal file
View File

@@ -0,0 +1,29 @@
---
icon: material/pulse
tags: ["сайт"]
---
# :material-pulse: Статус сервиса
Так выглядит статусная страница сервиса.
Попасть на неё можно по ссылке "[Аптайм](https://status.m3u.su)" в шапке сайта.
![Скриншот с примером главной страницы на десктопе](../assets/img/status/main.jpg)
Здесь отображается состояние компонентов сервиса:
* веб-интерфейс (то, что открывается в браузере);
* чекер (фоновая проверка плейлистов с помощью [iptvc](iptvc/index.md));
* кэш (база данных с временными данными о результатах проверки плейлистов).
Шкалы движутся во времени справа налево.
Они должны быть зелёными, а статус компонента должен быть «Healthy».
Каждое деление на шкале приблизительно равно 10 минутам между проверками.
Можно нажать на незвание сервиса и посмотреть детальную информацию:
![Скриншот с примером страницы компонента на десктопе](../assets/img/status/details.jpg)
Если на шкале появляется красное деление, значит был кратковременный сбой.
Но если вместо зелёного преобладают красные цвета, значит на сервере что-то основательно сломалось.

View File

@@ -6,46 +6,38 @@ icon: material/hand-heart-outline
Проект держится только на сугубо техническом интересе одного разработчика в свободное от работы время. Проект держится только на сугубо техническом интересе одного разработчика в свободное от работы время.
При этом, проект не планировался как монетизируемый и до сих пор не принёс ни рубля прибыли. Проект сознательно не монетизируется: это неправильно по отношению к пользователям и правообладателям.
Если у вас есть желание помочь проекту, ниже перечислены минимально доступные тебе способы — от самых простых способов к более сложным. Ниже перечислены минимально доступные вам способы — от самых простых к более сложным.
## Рассказать публично ## :simple-telegram: Подписаться в Telegram
Друзьям, коллегам, на своей страничке, в своих каналах и социальных сетях.
Вокруг проекта должно быть какое-то сообщество неравнодушных энтузиастов.
Только такие люди обеспечивают прогресс.
## Подписаться в Telegram
У проекта есть два публичных ресурса для прямой связи с пользователями. У проекта есть два публичных ресурса для прямой связи с пользователями.
Там можно ставить **платные реакции** к постам и/или **дарить голоса** (бусты): Там можно ставить **платные реакции** к постам и/или **дарить голоса** (бусты):
* канал: [@iptv_aggregator](https://t.me/iptv_aggregator) ([boost](https://t.me/iptv_aggregator?boost)) — в нём новости о проекте (общие объявления и проведённые доработки); * канал: [@iptv_aggregator](https://t.me/iptv_aggregator) ([boost](https://t.me/iptv_aggregator?boost)) — в нём новости о проекте (общие объявления и проведённые доработки);
* чат: [@iptv_aggregator_chat](https://t.me/iptv_aggregator_chat) ([boost](https://t.me/iptv_aggregator_chat?boost)) — комментарии к каналу, общение по теме проекта и IPTV. * чат: [@iptv_aggregator_chat](tg/chat.md) ([boost](https://t.me/iptv_aggregator_chat?boost)) — комментарии к каналу, общение по теме проекта и IPTV.
Голоса открывают новые возможности для каналов и групп. ## :material-wallet: Внести пожертвование
## Внести пожертвование Вы можете внести прямое денежное **пожертвование** с банковской карты на виртуальный кошелёк ЮMoney:
Вы можете внести прямое денежное **пожертвование** с банковской карты на виртуальный кошелёк ЮMoney. !!! yoomoney "[yoomoney.ru/to/41001685237530](https://yoomoney.ru/to/41001685237530)"
Разовый платёж, без подписок, на любую сумму. Разовый платёж, без подписок, на любую сумму.
<center><a href="https://yoomoney.ru/to/41001685237530">yoomoney.ru/to/41001685237530</a></center>
Также вы можете оформить подписку на Boosty: Также вы можете оформить подписку на Boosty:
<center><a href="https://boosty.to/anthonyaxenov">boosty.to/anthonyaxenov</a></center> !!! boosty "[boosty.to/anthonyaxenov](https://boosty.to/anthonyaxenov)"
Разовый платёж или платная подписка.
Финансовая поддержка проекта со стороны пользователей добровольна, она не рассматривается как способ обогащения или способ для эксклюзивного доступа к чему-либо. Пожертвования добровольны.
Они не дают права на эксклюзивный доступ к чему-либо и не рассматриваются как способ обогащения.
Это лишь попытка компенсировать затраты на содержание проекта.
Пожертвования являются лишь компенсацией трудозатрат и мотивацией к его технической поддержке и развитию. На пожертвования [был приобретён](https://t.me/iptv_aggregator/30) домен `m3u.su`, который сейчас используется в качестве основного адреса.
На пожертвования [был приобретён](https://t.me/iptv_aggregator/30) домен m3u.su, который сейчас используется в качестве короткого зеркала.
<a id="participate"></a> <a id="participate"></a>
## Принять участие в разработке ## :simple-git: Принять участие в разработке
Весь исходный код проекта хранится в репозиториях организации: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV) Весь исходный код проекта хранится в репозиториях организации: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV)
@@ -53,13 +45,13 @@ icon: material/hand-heart-outline
!!! info "Это бесплатно, но неактивированные учётки периодически удаляются." !!! info "Это бесплатно, но неактивированные учётки периодически удаляются."
### Создать задачу ### :octicons-issue-opened-16: Создать задачу
Любое ПО неидеально, как и документация к нему. Любое ПО неидеально, как и документация к нему.
Если вы нашли ошибку, опечатку, неожиданное поведение ПО или есть предложение по улучшению — можете создать задачу в соответствующем репозитории организации. Если вы нашли ошибку, опечатку, неожиданное поведение ПО или есть предложение по улучшению — можете создать задачу в соответствующем репозитории организации.
### Прислать изменения ### :octicons-git-pull-request-16: Прислать изменения
Вы можете внести исправления в код самостоятельно и прислать pull-request для принятия в основную ветку. Вы можете внести исправления в код самостоятельно и прислать pull-request для принятия в основную ветку.

View File

@@ -21,9 +21,13 @@ tags: ["telegram"]
* ❌ Никаких войсов, кружочков, игр, контактов, историй или локаций (предупреждение) * ❌ Никаких войсов, кружочков, игр, контактов, историй или локаций (предупреждение)
*Не удаляй свои сообщения, если на них успели ответить (предупреждение) *Не удаляй свои сообщения, если на них успели ответить (предупреждение)
🔶 Настоятельно рекомендуется прочесть хотя бы FAQ, а лучше всю документацию. Там наверняка уже давно есть ответ, который ты ищешь. Санитарка Роза или админ могут реагировать на твои сообщения и выдавать подсказки либо предупреждения (5 штук = бан). 🔶 Настоятельно рекомендуется прочесть хотя бы FAQ, а лучше всю документацию. Там наверняка уже давно есть ответ, который ты ищешь. Санитарка Роза или админ могут реагировать на твои сообщения и применять меры на своё усмотрение.
<a id="чеклист"></a> !!! failure "Не забывай"
К людям надо относиться по-человечески.
Твой юмор могут не понять, а пассивную агрессию и дерзость не любит никто.
<a id="checklist"></a>
## Я только спросить! ## Я только спросить!
Держи чеклист: Держи чеклист: