Files
web/views/list.twig

157 lines
8.3 KiB
Twig
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{###########################################################################
# Copyright (c) 2025, Антон Аксенов
# This file is part of m3u.su project
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
###########################################################################}
{% extends "template.twig" %}
{% block metadescription %}Самообновляемые бесплатные IPTV-плейлисты для домашнего просмотра по коротким ссылкам, списки каналов, проверка доступности{% endblock %}
{% block metakeywords %}самообновляемые,бесплатные,iptv-плейлисты,iptv,плейлисты{% endblock %}
{% block head %}
<style>
.card {transition: box-shadow .2s, transform .2s}
.card.hover-success:hover {transform: translateY(-7px); box-shadow: rgba(var(--bs-success-rgb), 1) 0 5px 20px -5px}
.card.hover-danger:hover {transform: translateY(-7px); box-shadow: rgba(var(--bs-danger-rgb), 1) 0 5px 20px -5px}
.card.hover-secondary:hover {transform: translateY(-7px); box-shadow: rgba(var(--bs-secondary-rgb), 1) 0 5px 20px -5px}
</style>
<script>
function setDefaultLogo(imgtag) {
imgtag.onerror = null
imgtag.src = '/no-tvg-logo.png'
}
</script>
{% endblock %}
{% block header %}
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
<div class="mb-2">
<h2 class="mb-0">Список плейлистов ({{ count }})</h2>
<div class="text-muted small">Изменён {{ updatedAt }} МСК</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="row g-4">
{% for code, playlist in playlists %}
{% set statusClass = 'secondary' %}
{% if playlist.isOnline is same as(true) %}
{% set statusClass = 'success' %}
{% elseif playlist.isOnline is same as(false) %}
{% set statusClass = 'danger' %}
{% endif %}
<div class="col-md-6 col-lg-4">
<div class="card bg-dark text-light h-100 border border-{{ statusClass }} hover-{{ statusClass }} position-relative">
<a href="/{{ code }}/details" class="text-decoration-none">
<div class="card-header d-flex align-items-center gap-2">
<span class="font-monospace text-{{ statusClass }}">{{ code }}</span>
{% if playlist.isOnline is same as(true) %}
<span class="cursor-help badge bg-{{ statusClass }} ms-auto"
title="Возможно, этот плейлист рабочий"
>online</span>
{% elseif playlist.isOnline is same as(false) %}
<span class="cursor-help badge bg-{{ statusClass }} ms-auto"
title="Этот плейлист нерабочий или его не удалось проверить"
>offline</span>
{% elseif playlist.isOnline is same as(null) %}
<span class="cursor-help badge bg-{{ statusClass }} ms-auto"
title="Плейлист ещё не проверялся, придётся подождать"
>unknown</span>
{% endif %}
{% if playlist.isOnline is same as(true) %}
<span class="cursor-help badge border border-success"
title="Процент рабочих каналов"
>{{ playlist.onlinePercent }}%</span>
{% endif %}
{% if "adult" in playlist.tags %}
<span class="cursor-help badge bg-warning text-dark"
title="Есть каналы для взрослых!"
>18+</span>
{% endif %}
{% if playlist.hasTokens is same as(true) %}
<span class="cursor-help badge bg-info text-dark"
title="В плейлисте есть каналы, которые могут быть нестабильны"
><ion-icon name="paw"></ion-icon></span>
{% endif %}
</div>
</a>
<div class="card-body position-relative z-2">
<a href="/{{ code }}/details" class="text-decoration-none">
<h5 class="card-title text-light">{{ playlist.name }}</h5>
</a>
{% if playlist.description is not same as(null) %}
<p class="card-text small text-secondary d-none d-md-block">{{ playlist.description }}</p>
{% endif %}
<div class="d-flex flex-wrap gap-2 mb-1">
{% if playlist.isOnline is same as(true) %}
<span class="badge border border-secondary">
<ion-icon name="videocam-outline" class="me-1"></ion-icon>&nbsp;{{ playlist.channels|length }}<span class="d-none d-xl-inline-block">&nbsp;каналов</span>
</span>
{% if playlist.groups|length > 0 %}
<span class="badge border border-secondary">
<ion-icon name="folder-open-outline" class="me-1"></ion-icon>&nbsp;{{ playlist.groups|length }}<span class="d-none d-xl-inline-block">&nbsp;групп</span>
</span>
{% endif %}
{% if playlist.hasTvg %}
<span class="badge border border-secondary">
<ion-icon name="newspaper-outline" class="me-1"></ion-icon><span class="d-none d-xl-inline-block">&nbsp;ТВ-программа</span>
</span>
{% endif %}
{% if playlist.hasCatchup %}
<span class="badge border border-secondary">
<ion-icon name="play-back-outline" class="me-1"></ion-icon><span class="d-none d-xl-inline-block">&nbsp;Архив</span>
</span>
{% endif %}
{% endif %}
</div>
</div>
<div class="card-footer cursor-pointer"
onclick="copyPlaylistUrl('{{ playlist.code }}')"
title="Нажми на ссылку, чтобы скопировать её в буфер обмена"
>
<div class="d-flex justify-content-between align-items-center small">
<span class="font-monospace text-truncate">
{{ base_url(playlist.code) }}
</span>
<ion-icon name="copy-outline"></ion-icon>
</div>
</div>
<a href="/{{ code }}/details" class="text-decoration-none">
</a>
</div>
</div>
{% endfor %}
</div>
{% if pageCount > 1 %}
<nav class="mt-4">
<ul class="pagination justify-content-center">
{% for page in range(1, pageCount) %}
{% if page == pageCurrent %}
<li class="page-item active" aria-current="page">
<span class="page-link">{{ page }}</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link bg-dark text-light" href="/page/{{ page }}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
</nav>
{% endif %}
{% endblock %}
{% block footer %}
{% endblock %}