Переработка под iptvc
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
{###########################################################################
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of iptv.axenov.dev web interface
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
###########################################################################}
|
||||
|
||||
{% extends "template.twig" %}
|
||||
|
||||
{% block title %}[{{ id }}] {{ name }} - {{ config('app.title') }}{% endblock %}
|
||||
{% block title %}[{{ playlist.code }}] {{ playlist.name }} - {{ config('app.title') }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
@@ -9,125 +15,395 @@
|
||||
td.chindex{width:1%}
|
||||
td.chlogo{width:100px}
|
||||
div.chlist-table{max-height:550px}
|
||||
textarea.m3u-raw{font-size:.7rem}
|
||||
</style>
|
||||
<script>
|
||||
function setDefaultLogo(imgtag) {
|
||||
imgtag.onerror = null
|
||||
imgtag.src = '{{ base_url('no-tvg-logo.png') }}'
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h2>О плейлисте: {{ name }}</h2>
|
||||
{% if (content.encoding.alert) %}
|
||||
<h2>О плейлисте: {{ playlist.name }}</h2>
|
||||
{% if (playlist.channels|length > 500) %}
|
||||
<div class="alert alert-warning small" role="alert">
|
||||
Кодировка исходного плейлиста отличается от UTF-8.
|
||||
Он был автоматически с конвертирован из {{ content.encoding.name }}, чтобы отобразить здесь список каналов.
|
||||
Однако названия каналов могут отображаться некорректно, причём не только здесь, но и в плеере.
|
||||
В плейлисте очень много каналов. На загрузку их списка и логотипов потребуется некоторое время.
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if (status.errCode > 0) %}
|
||||
{% if playlist.isOnline is same as(false) %}
|
||||
<div class="alert alert-danger small" role="alert">
|
||||
Ошибка плейлиста: [{{ status.errCode }}] {{ status.errText }}
|
||||
Ошибка плейлиста: {{ playlist.content }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<script src="{{ base_url('js/list.min.js') }}"></script>
|
||||
<script>
|
||||
var list = new List('chlist',{valueNames:['chname','chindex']});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-7">
|
||||
<table class="table table-dark table-hover small mb-lg-5">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="w-25" scope="row">ID</th>
|
||||
<td class="text-break">
|
||||
<code>{{ id }}</code> {% if status.possibleStatus == 'online' %}
|
||||
<span class="badge small text-dark bg-success">online</span>
|
||||
{% elseif status.possibleStatus == 'offline' %}
|
||||
<span class="badge small text-dark bg-danger">offline</span>
|
||||
{% elseif status.possibleStatus == 'timeout' %}
|
||||
<span class="badge small text-dark bg-warning">timeout</span>
|
||||
{% elseif status.possibleStatus == 'error' %}
|
||||
<span class="badge small text-dark bg-danger">error</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Описание</th>
|
||||
<td class="text-break"><p>{{ desc }}</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Ccылка для ТВ</th>
|
||||
<td><b onclick="prompt('Скопируй адрес плейлиста', '{{ url }}')"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Нажми на ссылку, чтобы скопировать её в буфер обмена"
|
||||
class="font-monospace cursor-pointer text-break">{{ url }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">M3U</th>
|
||||
<td class="text-break">{{ pls }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Источник</th>
|
||||
<td class="text-break">{{ src }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active"
|
||||
type="button"
|
||||
href="#tab-data"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#tab-data"
|
||||
>
|
||||
<ion-icon name="radio-outline"></ion-icon> Основные данные
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link"
|
||||
type="button"
|
||||
href="#tab-raw"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#tab-raw"
|
||||
>
|
||||
<ion-icon name="document-text-outline"></ion-icon> Исходный текст
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content small">
|
||||
<div class="tab-pane fade show active" id="tab-data" tabindex="0">
|
||||
<table class="table table-dark table-hover small mb-lg-5">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="w-25" scope="row">Код</th>
|
||||
<th class="text-break">
|
||||
{% if playlist.isOnline is same as(true) %}
|
||||
<span class="font-monospace text-success">{{ playlist.code }}</span>
|
||||
<span class="badge small text-dark bg-success">онлайн</span>
|
||||
{% elseif playlist.isOnline is same as(false) %}
|
||||
<span class="font-monospace text-danger">{{ playlist.code }}</span>
|
||||
<span class="badge small text-dark bg-danger">оффлайн</span>
|
||||
{% elseif playlist.isOnline is same as(null) %}
|
||||
<span class="font-monospace">{{ playlist.code }}</span>
|
||||
<span class="badge small text-dark bg-secondary" title="Не проверялся">unknown</span>
|
||||
{% endif %}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Описание</th>
|
||||
<td class="text-break"><p class="mb-0">{{ playlist.description }}</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Ccылка для ТВ</th>
|
||||
<td><b onclick="prompt('Скопируй адрес плейлиста', 'm3u.su/{{ playlist.code }}')"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Нажми на ссылку, чтобы скопировать её в буфер обмена"
|
||||
class="font-monospace cursor-pointer text-break">m3u.su/{{ playlist.code }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Источник</th>
|
||||
<td class="text-break">{{ playlist.source }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Наполнение</th>
|
||||
<td class="text-break">
|
||||
группы: {{ playlist.groups|length }},
|
||||
каналы: {{ playlist.channels|length }}
|
||||
(<span class="text-success">{{ playlist.onlineCount }}</span> + <span class="text-danger">{{ playlist.offlineCount }}</span>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Возможности</th>
|
||||
<td class="text-break">
|
||||
<ion-icon name="newspaper-outline"></ion-icon> Программа передач: {{ playlist.hasTvg ? 'есть' : 'нет' }}<br>
|
||||
<ion-icon name="play-back"></ion-icon> Перемотка (архив): {{ playlist.hasCatchup ? 'есть' : 'нет' }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="text-secondary">
|
||||
<th scope="row">M3U</th>
|
||||
<td class="text-break">{{ playlist.url }}</td>
|
||||
</tr>
|
||||
<tr class="text-secondary">
|
||||
<th class="w-25" scope="row">Проверка плейлиста</th>
|
||||
<td class="text-break">
|
||||
<span title="Фактическая метка времени окончания проверки плейлиста">
|
||||
{{ to_date(playlist.checkedAt) }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% if playlist.isOnline is same as(false) %}
|
||||
<tr class="text-secondary">
|
||||
<th class="w-25" scope="row">Ошибка проверки</th>
|
||||
<td class="text-break">{{ playlist.content }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if (content.attributes) %}
|
||||
<h4>Дополнительные атрибуты</h4>
|
||||
<table class="table table-dark table-hover small">
|
||||
<tbody>
|
||||
{% for attribute,value in content.attributes %}
|
||||
<tr>
|
||||
<th class="w-25" scope="row">{{ attribute }}</th>
|
||||
<td class="text-break">{{ value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% if (playlist.content.attributes) %}
|
||||
<h4>Дополнительные атрибуты</h4>
|
||||
<table class="table table-dark table-hover small font-monospace">
|
||||
<tbody>
|
||||
{% for attribute,value in playlist.attributes %}
|
||||
<tr>
|
||||
<th class="w-25" scope="row">{{ attribute }}</th>
|
||||
<td class="text-break">{{ value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab-raw" tabindex="1">
|
||||
<button class="btn btn-sm btn-success my-3"
|
||||
id="saveM3UBtn"
|
||||
onclick="savePlaylist('{{ playlist.code }}')"
|
||||
>
|
||||
<ion-icon name="download-outline"></ion-icon> Скачать файл {{ playlist.code }}.m3u8
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-light my-3"
|
||||
id="saveM3UBtn"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#qrcode-popup"
|
||||
>
|
||||
<ion-icon name="qr-code-outline"></ion-icon> Скачать по QR-коду
|
||||
</button>
|
||||
<textarea class="form-control bg-dark text-light font-monospace m3u-raw"
|
||||
rows="40"
|
||||
id="m3u-raw"
|
||||
readonly
|
||||
>{{ playlist.content }}</textarea>
|
||||
<div class="modal fade" id="qrcode-popup" tabindex="-1">
|
||||
<div class="modal-dialog ">
|
||||
<div class="modal-content bg-dark">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5">QR-код со ссылкой на плейлист</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<img src="{{ base_url(playlist.code ~ '/qrcode') }}" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-5">
|
||||
<h4>Список каналов ({{ content.channelCount ?? 0 }})</h4>
|
||||
{% if (content.channelCount > 0) %}
|
||||
<div id="chlist">
|
||||
<input type="text"
|
||||
class="form-control form-control-sm bg-dark text-light mb-2 fuzzy-search"
|
||||
placeholder="Поиск..."
|
||||
/>
|
||||
<h4>Список каналов: <span id="chcount">{{ playlist.channels|length }}</span></h4>
|
||||
{% if (playlist.channels|length > 0) %}
|
||||
{% if (playlist.groups|length > 1) %}
|
||||
<div class="row my-3">
|
||||
<div class="col-12">
|
||||
<div class="input-group">
|
||||
<select id="groupSelector"
|
||||
class="form-select form-select-sm border-secondary bg-dark text-light"
|
||||
onchange="updateFilter()"
|
||||
>
|
||||
<option selected value="all">Все группы</option>
|
||||
{% for group in playlist.groups %}
|
||||
<option value="{{ group.id }}">{{ group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<button type="button"
|
||||
onclick="resetGroup()"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
title="Сбросить группу"
|
||||
>
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row my-3">
|
||||
<div class="col-12">
|
||||
<div class="input-group">
|
||||
<input type="text"
|
||||
id="search-field"
|
||||
class="form-control form-control-sm border-secondary bg-dark text-light fuzzy-search"
|
||||
placeholder="Поиск каналов..."
|
||||
title="Начни вводить название"
|
||||
/>
|
||||
|
||||
<input type="radio"
|
||||
class="btn-check"
|
||||
name="chFilter"
|
||||
id="chfAll"
|
||||
autocomplete="off"
|
||||
onclick="updateFilter()"
|
||||
checked
|
||||
>
|
||||
<label class="btn btn-sm btn-outline-secondary"
|
||||
for="chfAll"
|
||||
title="Выбрать все каналы"
|
||||
>
|
||||
<ion-icon name="radio-button-on-outline"></ion-icon>
|
||||
</label>
|
||||
|
||||
<input type="radio"
|
||||
class="btn-check"
|
||||
name="chFilter"
|
||||
id="chfOnline"
|
||||
autocomplete="off"
|
||||
onclick="updateFilter()"
|
||||
>
|
||||
<label class="btn btn-sm btn-outline-success"
|
||||
for="chfOnline"
|
||||
title="Выбрать только онлайн каналы"
|
||||
>
|
||||
<ion-icon name="radio-button-on-outline"></ion-icon>
|
||||
</label>
|
||||
|
||||
<input type="radio"
|
||||
class="btn-check"
|
||||
name="chFilter"
|
||||
id="chfOffline"
|
||||
autocomplete="off"
|
||||
onclick="updateFilter()"
|
||||
>
|
||||
<label class="btn btn-sm btn-outline-danger"
|
||||
for="chfOffline"
|
||||
title="Выбрать только оффлайн каналы"
|
||||
>
|
||||
<ion-icon name="radio-button-on-outline"></ion-icon>
|
||||
</label>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
onclick="resetSearch()"
|
||||
title="Сбросить фильтрацию"
|
||||
>
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chlist-table overflow-auto">
|
||||
<table class="table table-dark table-hover small">
|
||||
<table id="chlist" class="table table-dark table-hover small">
|
||||
<tbody class="list">
|
||||
{% for channel in content.channels %}
|
||||
<tr class="chrow">
|
||||
{% for channel in playlist.channels %}
|
||||
<tr class="chrow"
|
||||
data-id="{{ channel.id }}"
|
||||
data-group="{{ channel.groupId ?? 'all' }}"
|
||||
data-online="{{ channel.isOnline ? 1 : 0 }}"
|
||||
title="
HTTP: {{ channel.status ?: '(неизвестно)' }}
Error: {{ channel.error ?: '(нет)' }}"
|
||||
>
|
||||
<td class="chindex">{{ loop.index }}</td>
|
||||
|
||||
<td class="chlogo text-center">
|
||||
<img class="tvg-logo"
|
||||
{% if (channel.logo.base64) %}
|
||||
src="{{ channel.logo.base64 }}"
|
||||
{% elseif (channel.attributes['tvg-logo']) %}
|
||||
src="{{ base_url('logo?url=' ~ channel.attributes['tvg-logo']) }}"
|
||||
loading="lazy"
|
||||
{% if (channel.attributes['tvg-logo']) %}
|
||||
<img class="tvg-logo"
|
||||
alt="Логотип канала '{{ channel.title }}'"
|
||||
title="Логотип канала '{{ channel.title }}'"
|
||||
src="{{ channel.attributes['tvg-logo'] }}"
|
||||
onerror="setDefaultLogo(this)"
|
||||
/>
|
||||
{% else %}
|
||||
src="{{ base_url('no-tvg-logo.png') }}"
|
||||
<img class="tvg-logo"
|
||||
alt="Нет логотипа для канала '{{ channel.title }}'"
|
||||
title="Нет логотипа для канала '{{ channel.title }}'"
|
||||
src="{{ base_url('no-tvg-logo.png') }}"
|
||||
/>
|
||||
{% endif %}
|
||||
alt="Логотип канала '{{ channel.name }}'"
|
||||
title="Логотип канала '{{ channel.name }}'"
|
||||
/>
|
||||
</td>
|
||||
<td class="chname text-break">{{ channel.name }}</td>
|
||||
|
||||
<td class="text-break">
|
||||
<ion-icon name="radio-button-on-outline"
|
||||
{% if (channel.isOnline) %}
|
||||
class="me-1 text-success"
|
||||
title="Состояние: онлайн"
|
||||
{% else %}
|
||||
class="me-1 text-danger"
|
||||
title="Состояние: оффлайн"
|
||||
{% endif %}
|
||||
|
||||
></ion-icon> <span class="chname">{{ channel.title }}</span>
|
||||
<div class="text-secondary small">
|
||||
{% if (channel.attributes['tvg-id']) %}
|
||||
<div title="tvg-id">
|
||||
<ion-icon name="star-outline" class="me-1"></ion-icon> {{ channel.attributes['tvg-id'] }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if (channel.contentType != null) %}
|
||||
<div title="MIME type">
|
||||
<ion-icon name="eye-outline" class="me-1"></ion-icon> {{ channel.contentType }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if channel.tags|length > 0 %}
|
||||
<ion-icon name="pricetag-outline" class="me-1"></ion-icon>
|
||||
{% for tag in channel.tags %}
|
||||
<span class="chtag">#{{ tag }}</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<script src="{{ base_url('js/list.min.js') }}"></script>
|
||||
<script>
|
||||
const options = {
|
||||
valueNames: [
|
||||
'chname',
|
||||
'chtag',
|
||||
{data: ['online', 'group']}
|
||||
],
|
||||
};
|
||||
|
||||
const list = new List('chlist', options)
|
||||
list.on('updated', (data) => document.getElementById('chcount').innerText = data.visibleItems.length)
|
||||
document.getElementById('search-field').addEventListener('keyup', (e) => list.search(e.target.value))
|
||||
|
||||
function savePlaylist() {
|
||||
const link = document.createElement("a");
|
||||
const content = document.getElementById("m3u-raw").value
|
||||
const file = new Blob([content], { type: 'text/plain' });
|
||||
link.href = URL.createObjectURL(file);
|
||||
link.download = "{{ playlist.code }}.m3u8";
|
||||
link.click();
|
||||
URL.revokeObjectURL(link.href);
|
||||
}
|
||||
|
||||
function resetGroup() {
|
||||
document.getElementById('groupSelector').value = 'all'
|
||||
updateFilter()
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
list.search('')
|
||||
document.getElementById('search-field').value = ''
|
||||
const elementById = document.getElementById('chfAll');
|
||||
elementById.checked = true
|
||||
updateFilter()
|
||||
}
|
||||
|
||||
function updateFilter() {
|
||||
const groupHash = document.getElementById('groupSelector')?.value ?? 'all';
|
||||
const activeType = document.querySelector('input[name="chFilter"]:checked').id;
|
||||
switch (activeType) {
|
||||
case 'chfAll':
|
||||
list.filter(item => item.values().group === groupHash || groupHash === 'all')
|
||||
break
|
||||
case 'chfOnline':
|
||||
list.filter(
|
||||
item => (item.values().group === groupHash || groupHash === 'all')
|
||||
&& item.values().online === '1'
|
||||
)
|
||||
break
|
||||
case 'chfOffline':
|
||||
list.filter(
|
||||
item => (item.values().group === groupHash || groupHash === 'all')
|
||||
&& item.values().online === '0'
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
519
views/faq.twig
519
views/faq.twig
@@ -1,5 +1,16 @@
|
||||
{###########################################################################
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of iptv.axenov.dev web interface
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
###########################################################################}
|
||||
|
||||
{% extends "template.twig" %}
|
||||
|
||||
{% block head %}
|
||||
<script async type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
|
||||
<script async nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h2>FAQ</h2>
|
||||
{% endblock %}
|
||||
@@ -7,19 +18,20 @@
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>
|
||||
<p class="mb-5">
|
||||
В этом сервисе собраны ссылки на IPTV-плейлисты, которые находятся в открытом доступе.
|
||||
Они отбираются вручную и постоянно проверяются здесь автоматически.
|
||||
Они отбираются вручную и периодически проверяются здесь автоматически.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
<p class="mb-5">
|
||||
Сервис "{{ config('app.title') }}" ({{ base_url() }}) не предназначен для хранения или трансляции
|
||||
видео/аудио потоков, программ телепередач, плейлистов и их поддержки. Этим занимаются администраторы
|
||||
ресурсов, указанные как источник, и те, с чьих ресурсов ведётся трансляция.
|
||||
</p>
|
||||
<p>
|
||||
За содержимое плейлистов и их качество отвечают авторы плейлистов. На стороне сервиса управляются сами
|
||||
плейлисты.
|
||||
|
||||
<p class="mb-5">
|
||||
</p>
|
||||
|
||||
<p class="mb-5">
|
||||
Сервис "{{ config('app.title') }}" ({{ base_url() }}) предоставляет только информацию об активности
|
||||
плейлистов, найденных в открытом доступе, и короткие ссылки на них для удобства использования в ПО.
|
||||
@@ -27,270 +39,269 @@
|
||||
тем, кто несёт за них ответственность (см. источники плейлистов).
|
||||
</p>
|
||||
|
||||
<div class="accordion" id="faq-accordion">
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header" id="h-purpose">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#purpose" aria-expanded="false" aria-controls="purpose">
|
||||
Для чего нужен сервис?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="purpose" class="accordion-collapse collapse" aria-labelledby="h-purpose" data-bs-parent="#faq-accordion">
|
||||
<div class="accordion-body">
|
||||
<p>Изначально сервис создавался "для себя", чтобы:</p>
|
||||
<ul>
|
||||
<li>сократить ссылки на сторонние плейлисты и их было проще вводить с пульта;</li>
|
||||
<li>собрать в одном месте наиболее годные плейлисты.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-5">
|
||||
Автор не занимается созданием, изменением, размещением и хранением плейлистов на сайте
|
||||
"{{ config('app.title') }}" ({{ base_url() }}). Ни бесплатно, ни за деньги, ни бартером, ни за спасибо.
|
||||
<b>Все плейлисты, которые отображаются на сайте "{{ config('app.title') }}" ({{ base_url() }}), созданы
|
||||
и размещены третьими лицами на чужих серверах.</b>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<p class="mb-5">
|
||||
Проект "{{ config('app.title') }}" ({{ base_url() }}) является бесплатным проектом с открытым исходным
|
||||
кодом, он публичен и открыт для всех. Весь его исходный код размещён в публичных репозиториях под
|
||||
лицензией MIT.
|
||||
</p>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header" id="h-howtouse">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#howtouse" aria-expanded="false" aria-controls="howtouse">
|
||||
Как пользоваться сервисом?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="howtouse" class="accordion-collapse collapse" aria-labelledby="h-howtouse" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
На главной странице отображается список доступных в плейлистов, их идентификаторы, статусы,
|
||||
количество каналов и короткие ссылки.
|
||||
Для просмотра списка каналов следует нажать на ссылку <b>"Подробнее..."</b> под интересующим плейлистом.
|
||||
Для добавления плейлиста в свой медиаплеер удобно использовать <b>"Ссылку для ТВ"</b>.
|
||||
Это делается для удобства ввода, например, на телевизоре с пульта.
|
||||
На странице детальной информации также есть прямая ссылка на сам плейлист от источника.
|
||||
Можно использовать и её.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-5">
|
||||
Автор не взимает плату за размещение ссылок на сторонние плейлисты на сайте "{{ config('app.title') }}"
|
||||
({{ base_url() }}). За содержимое плейлистов и их качество отвечают авторы плейлистов.
|
||||
</p>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-howtoconnect">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#howtoconnect" aria-expanded="false" aria-controls="howtoconnect">
|
||||
Как подключить плейлист?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="howtoconnect" class="accordion-collapse collapse" aria-labelledby="h-howtoconnect" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
<a href="https://www.google.com/search?q=%D0%BA%D0%B0%D0%BA%20%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B8%D1%82%D1%8C%20iptv%20%D0%BF%D0%BB%D0%B5%D0%B9%D0%BB%D0%B8%D1%81%D1%82%20%D0%BF%D0%BE%20%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B5">
|
||||
Добавь в свой медиаплеер</a> "Ссылку для ТВ".
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-5">
|
||||
Автор не зарабатывает на проекте "{{ config('app.title') }}" ({{ base_url() }}) и не собирается.
|
||||
Всё, что ты видишь по этому адресу, сделано бесплатно и на энтузиазме.
|
||||
Но ты можешь сделать добровольное пожертвование, которое поможет мне компенсировать затраты на
|
||||
поддержку и техническое развитие проекта. Ссылки в шапке сайта.
|
||||
</p>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-isitfree">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#isitfree" aria-expanded="false" aria-controls="isitfree">
|
||||
Эти плейлисты и каналы в них -- бесплатны?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="isitfree" class="accordion-collapse collapse" aria-labelledby="h-isitfree" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Возможно. По крайней мере, так утверждают источники. Но гарантий никаких никто не даёт.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Для чего нужен сервис? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="why">
|
||||
<h2>Для чего нужен сервис?</h2>
|
||||
<p>Изначально сервис создавался "для себя", чтобы:</p>
|
||||
<ul>
|
||||
<li>сократить ссылки на сторонние плейлисты и их было проще вводить с пульта;</li>
|
||||
<li>собрать в одном месте наиболее годные плейлисты.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Сейчас я сам им не пользуюсь, но им пользуются сотни людей ежедневно, чтобы найти
|
||||
плейлист себе по душе или по необходимости. Например, чтобы смотреть заблокированные российские
|
||||
телеканалы в свободной демократической европе.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header" id="h-logos">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#logos" aria-expanded="false" aria-controls="logos">
|
||||
Откуда берутся логотипы каналов и программы передач?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="logos" class="accordion-collapse collapse" aria-labelledby="h-logos" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Всё это (не) указывается внутри плейлиста его авторами.
|
||||
Но в некоторых плеерах можно вручную указывать программу передач (см. ниже).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Как пользоваться сервисом? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="how">
|
||||
<h2>Как пользоваться сервисом?</h2>
|
||||
<p>
|
||||
На главной странице отображается список доступных в плейлистов, их идентификаторы, статусы,
|
||||
количество каналов и короткие ссылки.
|
||||
Для просмотра списка каналов следует нажать на ссылку <b>"Подробнее..."</b> под интересующим
|
||||
плейлистом.
|
||||
Для добавления плейлиста в свой медиаплеер удобно использовать <b>"Ссылку для ТВ"</b>.
|
||||
На странице детальной информации также есть прямая ссылка на сам плейлист от источника.
|
||||
Можно использовать и её.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-which">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#which" aria-expanded="false" aria-controls="which">
|
||||
Какие плейлисты попадают сюда?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="which" class="accordion-collapse collapse" aria-labelledby="h-which" data-bs-parent="#faq-accordion">
|
||||
<div class="accordion-body">
|
||||
<p>Есть некоторые критерии, по которым плейлисты отбираются в этот список:</p>
|
||||
<ul>
|
||||
<li>Прежде всего -- каналы РФ и бывшего СНГ, но не только</li>
|
||||
<li>Открытый источник</li>
|
||||
<li>Прямая ссылка на плейлист</li>
|
||||
<li>Автообновление плейлиста</li>
|
||||
</ul>
|
||||
<p>
|
||||
В основном, в плейлистах именно трансляции телеканалов, но могут быть просто список каких-то
|
||||
(мульт)фильмов и передач, находящихся на чужих дисках (как если бы вы сами составили плейлист с музыкой,
|
||||
например).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Какие плейлисты попадают сюда? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="which">
|
||||
<h2>Какие плейлисты попадают сюда?</h2>
|
||||
<p>Есть некоторые критерии, по которым плейлисты отбираются в этот список:</p>
|
||||
<ul>
|
||||
<li>Прежде всего -- каналы РФ и бывшего СНГ, но не только</li>
|
||||
<li>Открытый источник</li>
|
||||
<li>Прямая ссылка на плейлист</li>
|
||||
<li>Автообновление плейлиста</li>
|
||||
</ul>
|
||||
<p>
|
||||
В основном, в плейлистах именно трансляции телеканалов, но могут быть просто список каких-то
|
||||
(мульт)фильмов и передач, находящихся на чужих дисках (как если бы вы сами составили плейлист с музыкой,
|
||||
например).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-statuses">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#statuses" aria-expanded="false" aria-controls="statuses">
|
||||
Что означают статусы плейлистов?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="statuses" class="accordion-collapse collapse" aria-labelledby="h-statuses" data-bs-parent="#faq-accordion">
|
||||
<div class="accordion-body">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-secondary">loading</span>
|
||||
Загрузка данных, нужно немного подождать.
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-success">online</span>
|
||||
Плейлист, возможно, активен. <i>Если каналов 0, значит, вероятно, источник поставил
|
||||
редирект с плейлиста на куда ему вздумалось. То есть плейлист, наверное, отсутствует
|
||||
и, возможно, больше никогда не появится по текущему адресу.</i>
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-warning">timeout</span>
|
||||
Не удалось вовремя проверить плейлист, сервер с плейлистом слишком долго запрягает.
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-danger">offline</span>
|
||||
Плейлист недоступен, вообще.
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-danger">error</span>
|
||||
Ошибка при проверке плейлиста. Пора удалять плейлист отсюда.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Что означают статусы? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="statuses">
|
||||
<h2>Что означают статусы?</h2>
|
||||
<p>Плейлист может быть в одном из трёх статусов:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-secondary">unknown</span>
|
||||
Плейлист ещё не проверялся, можно зайти позже.
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-success">online</span>
|
||||
Плейлист активен. Это не значит, что он работает. В нём может быть 0 каналов.
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge small text-dark bg-danger">offline</span>
|
||||
Плейлист недоступен, вообще никак. Главный кандидат на удаление с сайта.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Каждый канал в плейлисте может быть в одном из трёх статусов:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="text-success"><ion-icon name="radio-button-on-outline"></ion-icon></span>
|
||||
Канал активен. Это не значит, что он работает. Там может транслироваться какая-нибудь заглушка (например, от Wink).
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-danger"><ion-icon name="radio-button-on-outline"></ion-icon></span>
|
||||
Канал не работает.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Я не гарантирую корректность и актуальность информации, которую ты увидишь здесь.
|
||||
Хотя я и стараюсь улучшать качество проверок, но всё же рекомендую проверять желаемые
|
||||
плейлисты самостоятельно вручную, ибо нет никаких гарантий:
|
||||
</p>
|
||||
<ul>
|
||||
<li>что плейлисты по разным ссылкам не дублируют друг друга и отличаются каналами хотя бы на четверть;</li>
|
||||
<li>что плейлист работоспособен (каналы работают, корректно названы, имеют аудио, etc.);</li>
|
||||
<li>что подгрузится корректное количество каналов и их список.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-donttrust">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#donttrust" aria-expanded="false" aria-controls="donttrust">
|
||||
Почему нельзя доверять результатам проверки?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="donttrust" class="accordion-collapse collapse" aria-labelledby="h-donttrust" data-bs-parent="#faq-accordion">
|
||||
<div class="accordion-body">
|
||||
<p>
|
||||
Я не гарантирую корректность и актуальность информации, которую ты увидишь здесь.
|
||||
Хотя я и стараюсь улучшать качество проверок, но всё же рекомендую проверять желаемые
|
||||
плейлисты самостоятельно вручную, ибо нет никаких гарантий:
|
||||
</p>
|
||||
<ul>
|
||||
<li>что это вообще плейлисты, а не чьи-то архивы с мокрыми кисками;</li>
|
||||
<li>что плейлисты по разным ссылкам не дублируют друг друга и отличаются каналами хотя бы на четверть;</li>
|
||||
<li>что плейлист работоспособен (каналы работают, корректно названы, имеют аудио, etc.);</li>
|
||||
<li>что подгрузится корректное количество каналов и их список (хотя на это я ещё могу влиять и стараюсь как-то улучшить).</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Как часто обновляется список плейлистов? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="how-often-list">
|
||||
<h2>Как часто обновляется список плейлистов?</h2>
|
||||
<p>
|
||||
Время от времени.
|
||||
Иногда я захожу сюда и проверяю всё ли на месте, иногда занимаюсь какими-то доработками.
|
||||
Если есть кандидаты на добавление, то читай ниже.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-guarantee">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#guarantee" aria-expanded="false" aria-controls="guarantee">
|
||||
Какова гарантия, что я добавлю себе плейлист отсюда и он работать хоть сколько-нибудь долго?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="guarantee" class="accordion-collapse collapse" aria-labelledby="h-guarantee" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Никакова.
|
||||
Мёртвые плейлисты я периодически вычищаю, реже -- добавляю новые.
|
||||
ID плейлистов могут меняться, поэтому вполне может произойти внезапная подмена одного другим, однако
|
||||
намеренно я так не делаю.
|
||||
Если один плейлист переезжает на новый адрес, то я ставлю временное перенаправление со старого ID на
|
||||
новый.
|
||||
Плюс читай выше про доверие результатам проверки (проблема может быть не стороне сервиса).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Как часто обновляется содержимое плейлистов? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="how-often-chan">
|
||||
<h2>Как часто обновляется содержимое плейлистов?</h2>
|
||||
<p>Зависит от источника. Я этим не занимаюсь.</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header" id="h-panic">
|
||||
<button class="accordion-button text-warning bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#panic" aria-expanded="false" aria-controls="panic">
|
||||
У меня перестал работать/исчез любимый канал/плейлист! Нет лого канала/программы передач!
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panic" class="accordion-collapse collapse" aria-labelledby="h-panic" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">Ну штош ¯\_(ツ)_/¯</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Есть приложение? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="app">
|
||||
<h2>Есть приложение?</h2>
|
||||
<p>Нет, и не планируется. Ищи плеер и добавляй плейлист туда по ссылке.</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-epg">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#epg" aria-expanded="false" aria-controls="epg">
|
||||
Где взять программу передач (EPG)?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="epg" class="accordion-collapse collapse" aria-labelledby="h-epg" data-bs-parent="#faq-accordion">
|
||||
<div class="accordion-body">
|
||||
<ul>
|
||||
<li><b>https://iptvx.one/viewtopic.php?f=12&t=4</b></li>
|
||||
<li>https://iptvmaster.ru/epg-for-iptv</li>
|
||||
<li>https://google.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Эти плейлисты и каналы в них -- бесплатны? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="is-pls-free">
|
||||
<h2>Эти плейлисты и каналы в них -- бесплатны?</h2>
|
||||
<p>
|
||||
Возможно. По крайней мере, так утверждают источники, которые их распространяют.
|
||||
Но гарантий никаких никто не даёт. Любой плейлист и любой канал в любом плейлисте может сдохнуть
|
||||
навсегда в любой момент. Или показывать заглушку.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-howoftenlist">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#howoftenlist" aria-expanded="false" aria-controls="howoftenlist">
|
||||
Как часто обновляется список плейлистов?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="howoftenlist" class="accordion-collapse collapse" aria-labelledby="h-howoftenlist" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Время от времени.
|
||||
Иногда я захожу сюда и проверяю всё ли на месте, иногда занимаюсь какими-то доработками.
|
||||
Если есть кандидаты на добавление, то читай ниже.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Заглушка 1 -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="paywall1">
|
||||
<h2 class="text-warning">
|
||||
На канале отображается заглушка:<br /><br />
|
||||
<span class="fst-italic">"Уважаемый клиент! Для возобновления просмотра Вам необходимо использовать не более 2 устройств"</span><br /><br />
|
||||
или<br /><br />
|
||||
<span class="fst-italic">"Ваша подписка не активна"</span>
|
||||
</h2>
|
||||
<p>Кто-то воткнул платный канал в плейлист и распространил его как бесплатный.</p>
|
||||
<p>Забудь про этот плейлист. Ищи другой. Без вариантов. Такова цена халявы.</p>
|
||||
<p>Нет, я не буду это исправлять.</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-howoftench">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#howoftench" aria-expanded="false" aria-controls="howoftench">
|
||||
Как часто обновляется содержимое плейлистов?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="howoftench" class="accordion-collapse collapse" aria-labelledby="h-howoftench" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Зависит от источника. Я этим не занимаюсь.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Заглушка 2 -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="paywall2">
|
||||
<h2 class="text-warning">
|
||||
На канале отображается заглушка:<br /><br />
|
||||
<span class="fst-italic">"Просмотр ТВ-каналов, фильмов и сериалов доступен только в официальных приложения Wink и на территории России"</span>
|
||||
</h2>
|
||||
<p>Кто-то воткнул платный канал в плейлист и распространил его как бесплатный.</p>
|
||||
<p>Попробуй использовать плеер, который позволяет указать User-Agent, и указать User-Agent:</p>
|
||||
<pre class="fw-bold">Mozilla/5.0 WINK/1.31.1 (AndroidTV/9) HlsWinkPlayer</pre>
|
||||
<p>Или подключи Wink. Или забудь про этот плейлист и ищи другой.</p>
|
||||
<p>Нет, я не буду это исправлять.</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-api">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#api" aria-expanded="false" aria-controls="api">
|
||||
Есть ли API? Как им пользоваться?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="api" class="accordion-collapse collapse" aria-labelledby="h-api" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Есть, подробности <a href="https://github.com/anthonyaxenov/iptv2#api">здесь</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Добавь канал! -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="add-chan">
|
||||
<h2 class="text-danger">Добавь канал!</h2>
|
||||
<p class="h1 my-5">Нет.</p>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item bg-dark text-light">
|
||||
<h2 class="accordion-header bg-dark" id="h-howtoadd">
|
||||
<button class="accordion-button text-light bg-dark" type="button" data-bs-toggle="collapse" data-bs-target="#howtoadd" aria-expanded="false" aria-controls="howtoadd">
|
||||
Как пополнить этот список?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="howtoadd" class="accordion-collapse collapse" aria-labelledby="h-howtoadd" data-bs-parent="#faq-accordion">
|
||||
<p class="accordion-body">
|
||||
Сделать pull-request в <a href="https://github.com/anthonyaxenov/iptv">репозиторий</a>.
|
||||
Я проверю плейлист и добавлю его в общий список, если всё ок.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Добавь плейлист! -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="create-list">
|
||||
<h2 class="text-danger">Сделай плейлист!</h2>
|
||||
<p class="h1 my-5">Нет.</p>
|
||||
</div>
|
||||
|
||||
<!-- Откуда берутся логотипы каналов и программы передач? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="logos">
|
||||
<h2>Откуда берутся логотипы каналов и программы передач?</h2>
|
||||
<p>
|
||||
Всё это (не) указывается внутри плейлиста его авторами.
|
||||
Но в некоторых плеерах можно вручную указывать программу передач (см. ниже).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Нет лого канала! -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="channel-no-logo">
|
||||
<h2>Нет лого канала!</h2>
|
||||
<p>Грустно ¯\_(ツ)_/¯</p>
|
||||
</div>
|
||||
|
||||
<!-- Где спортивные каналы? Почему они не работают? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="sport">
|
||||
<h2 class="text-primary">Где спортивные каналы? Почему они не работают?</h2>
|
||||
<p>
|
||||
Спортивные телеканалы очень пристально следят за тем, куда текут их трансляции. Они зарабатывают
|
||||
на спорте и активно защищают свои права на трансляцию каких-то уникальных спортивных состязаний и
|
||||
событий. Они активно рубят все левые источники, приходят к авторам плейлистов и любезно
|
||||
просят удалить любые упоминания, ссылки и трансляции их каналов из паблика. Поэтому некоторые
|
||||
авторы сразу предупреждают, что в плейлистах таких каналов нет. Судиться потом, вот это всё...
|
||||
нафиг надо.
|
||||
</p>
|
||||
<p>
|
||||
Нет, я не буду добавлять каналы в плейлисты.
|
||||
Если будет спортивный рабочий плейлист -- добавлю на сайт.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Какова гарантия, что я добавлю себе плейлист отсюда и он будет работать? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="guarantee">
|
||||
<h2>Какова гарантия, что я добавлю себе плейлист отсюда и он будет работать?</h2>
|
||||
<p>Никакова.</p>
|
||||
<p>Мёртвые плейлисты я периодически вычищаю, реже -- добавляю новые.
|
||||
ID плейлистов могут меняться, поэтому вполне может произойти внезапная подмена одного другим, однако
|
||||
это происходит редко.</p>
|
||||
<p>Если один плейлист переезжает на новый адрес, то я ставлю временное перенаправление со старого ID на
|
||||
новый.</p>
|
||||
<p>Плюс читай выше про доверие результатам проверки (проблема может быть не стороне сервиса).</p>
|
||||
</div>
|
||||
|
||||
<!-- У меня перестал работать/исчез любимый канал/плейлист! -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="down">
|
||||
<h2 class="text-danger">У меня перестал работать/исчез любимый канал/плейлист!</h2>
|
||||
<p>Ну штош ¯\_(ツ)_/¯</p>
|
||||
</div>
|
||||
|
||||
<!-- Где взять программу передач (EPG)? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="epg">
|
||||
<h2>Где взять программу передач (EPG)?</h2>
|
||||
<ul>
|
||||
<li><b>https://iptvx.one/viewtopic.php?f=12&t=4</b></li>
|
||||
<li>https://iptvmaster.ru/epg-for-iptv</li>
|
||||
<li>https://google.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- В плейлистах одна порнуха! -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="adult">
|
||||
<h2 class="text-danger">В плейлистах одна порнуха!</h2>
|
||||
<p>Ну, бывает, да. Смотри сколько хочешь. Или не смотри. Или не хоти.</p>
|
||||
<h2 class="text-danger">Но у меня же дети! Яжмать! Яжотец!</h2>
|
||||
<p>Я вот детям порнуху не показываю. Ты тоже не показывай.</p>
|
||||
</div>
|
||||
|
||||
<!-- Есть ли API? Как им пользоваться? -->
|
||||
{# <div class="alert my-5 bg-dark text-light border-secondary">#}
|
||||
{# <h2 id="api">Есть ли API? Как им пользоваться?</h2>#}
|
||||
{# <p>Есть, подробности <a href="https://github.com/anthonyaxenov/iptv2#api">здесь</a>.</p>#}
|
||||
{# </div>#}
|
||||
|
||||
<!-- Как добавить плейлист в список? -->
|
||||
<div class="alert my-5 bg-dark text-light border-secondary" id="pr">
|
||||
<h2>Как добавить плейлист в список?</h2>
|
||||
<p>
|
||||
Сделать pull-request в <a href="https://git.axenov.dev/IPTV/playlists">репозиторий</a>.
|
||||
Я проверю плейлист и добавлю его в общий список, если всё ок.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
{###########################################################################
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of iptv.axenov.dev web interface
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
###########################################################################}
|
||||
|
||||
{% extends "template.twig" %}
|
||||
|
||||
{% block header %}
|
||||
<p class="text-muted small">
|
||||
Обновлено: {{ updated_at }} МСК<br/>
|
||||
Плейлистов в списке: <strong>{{ count }}</strong>
|
||||
</p>
|
||||
<div class="row text-muted small">
|
||||
<div class="col-md">
|
||||
Состояние проверки:<br />
|
||||
<span class="me-1">
|
||||
<span class="badge me-1 bg-success text-dark">online</span>{{ onlineCount }}
|
||||
</span>
|
||||
<span class="me-1">
|
||||
<span class="badge me-1 bg-danger text-dark">offline</span>{{ offlineCount }}
|
||||
</span>
|
||||
<span class="me-1">
|
||||
<span class="badge me-1 bg-secondary text-dark">unknown</span>{{ uncheckedCount }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md">
|
||||
Обновлено: {{ updatedAt }} МСК<br/>
|
||||
Плейлистов в списке: <strong>{{ count }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
{% endblock %}
|
||||
|
||||
@@ -15,34 +35,58 @@
|
||||
<tr>
|
||||
<th class="text-center">ID</th>
|
||||
<th>Информация о плейлисте</th>
|
||||
<th class="text-center">Каналов</th>
|
||||
<th class="d-none d-sm-table-cell">Ссылка для ТВ</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for id, playlist in playlists %}
|
||||
<tr class="pls" data-playlist-id="{{ id }}">
|
||||
<td class="text-center font-monospace id">{{ id }}</td>
|
||||
{% for code, playlist in playlists %}
|
||||
<tr class="pls" data-playlist-code="{{ code }}">
|
||||
<td class="text-center font-monospace code">{{ code }}</td>
|
||||
<td class="info">
|
||||
<a href="{{ base_url(id ~ '/details') }}" class="text-light fw-bold text-decoration-none">{{ playlist.name }}</a>
|
||||
{% if playlist.isOnline is same as(true) %}
|
||||
<span class="badge small bg-success text-dark">online</span>
|
||||
{% elseif playlist.isOnline is same as(false) %}
|
||||
<span class="badge small bg-danger text-dark">offline</span>
|
||||
{% elseif playlist.isOnline is same as(null) %}
|
||||
<span class="badge small bg-secondary text-dark" title="Не проверялся">unknown</span>
|
||||
{% endif %}
|
||||
<a href="{{ base_url(code ~ '/details') }}" class="text-light fw-bold text-decoration-none">{{ playlist.name }}</a>
|
||||
<div class="small mt-2">
|
||||
{% if playlist.desc|length > 0 %}
|
||||
<p class="my-1 d-none d-lg-block">{{ playlist.desc }}</p>
|
||||
{% if playlist.description|length > 0 %}
|
||||
<p class="my-1 d-none d-lg-block">{{ playlist.description }}</p>
|
||||
{% endif %}
|
||||
<a href="{{ base_url(id ~ '/details') }}" class="text-light">Подробнее...</a>
|
||||
{% if playlist.tags|length > 0 %}
|
||||
<p class="my-1 d-none d-lg-block text-muted" title="Теги, присвоенные каналам при проверке">
|
||||
<ion-icon name="pricetag-outline" class="me-1"></ion-icon>
|
||||
{% for tag in playlist.tags %}
|
||||
<span class="chtag">#{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<a href="{{ base_url(code ~ '/details') }}" class="text-light">Подробнее...</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% if (playlist.isOnline is not same as(null)) %}
|
||||
{{ playlist.channels|length }}
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="col-3 d-none d-sm-table-cell">
|
||||
<span onclick="prompt('Скопируй адрес плейлиста', '{{ playlist.url }}')"
|
||||
<span onclick="prompt('Скопируй адрес плейлиста', 'm3u.su/{{ playlist.code }}')"
|
||||
title="Нажми на ссылку, чтобы скопировать её в буфер обмена"
|
||||
class="font-monospace cursor-pointer">
|
||||
{{ playlist.url }}
|
||||
class="font-monospace cursor-pointer"
|
||||
>
|
||||
m3u.su/{{ playlist.code }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if pageCount > 0 %}
|
||||
{% if pageCount > 1 %}
|
||||
<div aria-label="pages">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% for page in range(1, pageCount) %}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
{###########################################################################
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of iptv.axenov.dev web interface
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
###########################################################################}
|
||||
|
||||
{% extends "template.twig" %}
|
||||
|
||||
{% block header %}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
{###########################################################################
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of iptv.axenov.dev web interface
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
###########################################################################}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
@@ -6,7 +12,12 @@
|
||||
<meta name="description" content="Самообновляемые бесплатные IPTV-плейлисты для домашнего просмотра по коротким ссылкам, списки каналов, проверка доступности">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<style>.cursor-pointer{cursor:pointer}</style>
|
||||
<style>
|
||||
.cursor-pointer{cursor:pointer}
|
||||
.boosty{vertical-align:baseline;float:left;display:inline;width:20px}
|
||||
</style>
|
||||
<script async type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
|
||||
<script async nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
|
||||
<link href="{{ base_url('css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url('/favicon/apple-touch-icon.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ base_url('/favicon/favicon-32x32.png') }}">
|
||||
@@ -16,14 +27,13 @@
|
||||
<meta name="msapplication-TileColor" content="#00aba9">
|
||||
<meta name="msapplication-TileImage" content="{{ base_url('/favicon/mstile-144x144.png') }}">
|
||||
<meta name="theme-color" content="#212529">
|
||||
<style>.boosty{vertical-align:baseline;float:left;display:inline;width:20px}</style>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-dark text-light">
|
||||
<div class="container col-lg-8 mx-auto">
|
||||
<div class="container col-lg-10 mx-auto">
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<img src="{{ base_url('/favicon/favicon-32x32.png') }}" class="d-inline-block align-text-top px-lg-1" alt=""/>
|
||||
<img src="{{ base_url('/favicon/favicon-32x32.png') }}" class="d-inline-block px-lg-1" alt="Логотип проекта - emoji телевизора"/>
|
||||
<a class="navbar-brand" href="{{ base_url() }}" title="На главную">
|
||||
{{ config('app.title') }}
|
||||
</a>
|
||||
@@ -39,10 +49,7 @@
|
||||
<a class="nav-link" href="{{ base_url('faq') }}">FAQ</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://git.axenov.dev/anthony/iptv">Gitea</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/anthonyaxenov/iptv">GitHub</a>
|
||||
<a class="nav-link" href="https://git.axenov.dev/IPTV">Исходники</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://axenov.dev">axenov.dev</a>
|
||||
@@ -56,6 +63,12 @@
|
||||
Boosty
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://yoomoney.ru/to/41001685237530">
|
||||
<ion-icon name="card-outline"></ion-icon>
|
||||
Yoomoney
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -70,12 +83,16 @@
|
||||
<script src="{{ base_url('js/bootstrap.bundle.min.js') }}"></script>
|
||||
{% block footer %}{% endblock %}
|
||||
<a href="{{ base_url('faq') }}">FAQ</a> | <a
|
||||
href="https://github.com/anthonyaxenov/iptv">GitHub</a> | <a
|
||||
href="https://git.axenov.dev/anthony/iptv">Gitea</a> | <a
|
||||
href="https://git.axenov.dev/IPTV">Исходники</a> | <a
|
||||
href="https://axenov.dev">axenov.dev</a> | <a
|
||||
href="https://t.me/iptv_aggregator">Telegram</a><br>
|
||||
<a class="small text-secondary"
|
||||
href="https://git.axenov.dev/IPTV/web/releases/tag/v{{ version() }}"
|
||||
target="_blank"
|
||||
>v{{ version() }}</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
{% include("custom.twig") ignore missing %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user