Compare commits

..

4 Commits

8 changed files with 45 additions and 57 deletions

View File

@@ -21,6 +21,30 @@ use Psr\Http\Message\ServerRequestInterface;
*/ */
class ApiController extends BasicController class ApiController extends BasicController
{ {
/**
* Возвращает информацию о плейлисте
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
* @throws Exception
*/
public function getOne(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
try {
$code = $request->getAttributes()['code'] ?? null;
empty($code) && throw new PlaylistNotFoundException('');
$playlist = ini()->getPlaylist($code);
if ($playlist['isOnline'] === true) {
unset($playlist['content']);
}
return $this->responseJson($response, 200, $playlist);
} catch (PlaylistNotFoundException $e) {
return $this->responseJsonError($response, 404, $e);
}
}
/** /**
* Возвращает информацию о каналов плейлиста * Возвращает информацию о каналов плейлиста
* *
@@ -56,24 +80,4 @@ class ApiController extends BasicController
return $response->withStatus(200) return $response->withStatus(200)
->withHeader('Content-Type', $mime); ->withHeader('Content-Type', $mime);
} }
/**
* Возвращает информацию о плейлисте
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
* @throws Exception
*/
public function json(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$code = $request->getAttributes()['code'];
try {
$playlist = ini()->getPlaylist($code);
return $this->responseJson($response, 200, $playlist);
} catch (PlaylistNotFoundException $e) {
return $this->responseJsonError($response, 404, $e);
}
}
} }

View File

@@ -34,7 +34,7 @@ class BasicController
*/ */
public function notFound(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface public function notFound(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{ {
$code = $request->getAttributes()['code']; $code = $request->getAttributes()['code'] ?? '';
$response->withStatus(404); $response->withStatus(404);
$this->view($request, $response, 'notfound.twig', ['code' => $code]); $this->view($request, $response, 'notfound.twig', ['code' => $code]);

View File

@@ -63,21 +63,6 @@ class WebController extends BasicController
]); ]);
} }
/**
* Возвращает страницу FAQ
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
public function faq(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $this->view($request, $response, 'faq.twig');
}
/** /**
* Переадресует запрос на прямую ссылку плейлиста * Переадресует запрос на прямую ссылку плейлиста
* *

View File

@@ -41,7 +41,11 @@ class IniFile
// сохраняем порядок // сохраняем порядок
foreach (array_keys($ini) as $code) { foreach (array_keys($ini) as $code) {
$data = redis()->get($code); try {
$data = @redis()->get($code);
} catch (Throwable) {
$data = false;
}
if ($data === false) { if ($data === false) {
$raw = $ini[$code]; $raw = $ini[$code];
$data = [ $data = [

View File

@@ -6,6 +6,7 @@
*/ */
use App\Controllers\ApiController; use App\Controllers\ApiController;
use App\Controllers\BasicController;
use App\Controllers\BotController; use App\Controllers\BotController;
use App\Controllers\WebController; use App\Controllers\WebController;
@@ -35,12 +36,6 @@ return [
'handler' => [WebController::class, 'home'], 'handler' => [WebController::class, 'home'],
'name' => 'home', 'name' => 'home',
], ],
[
'method' => 'GET',
'path' => '/faq',
'handler' => [WebController::class, 'faq'],
'name' => 'faq',
],
[ [
'method' => 'GET', 'method' => 'GET',
'path' => '/{code:[0-9a-zA-Z]+}[.m3u[8]]', 'path' => '/{code:[0-9a-zA-Z]+}[.m3u[8]]',
@@ -62,13 +57,13 @@ return [
[ [
'method' => 'GET', 'method' => 'GET',
'path' => '/{code:[0-9a-zA-Z]+}/json', 'path' => '/api/playlists/{code:[0-9a-zA-Z]+}',
'handler' => [ApiController::class, 'json'], 'handler' => [ApiController::class, 'getOne'],
'name' => 'json', 'name' => 'api::getOne',
], ],
[ [
'method' => 'GET', 'method' => 'GET',
'path' => '/{code:[0-9a-zA-Z]+}/qrcode', 'path' => '/api/playlists/{code:[0-9a-zA-Z]+}/qrcode',
'handler' => [ApiController::class, 'makeQrCode'], 'handler' => [ApiController::class, 'makeQrCode'],
'name' => 'api::makeQrCode', 'name' => 'api::makeQrCode',
], ],

View File

@@ -175,7 +175,7 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body text-center"> <div class="modal-body text-center">
<img src="/{{ playlist.code }}/qrcode" alt=""> <img src="/api/playlists/{{ playlist.code }}/qrcode" alt="">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -70,26 +70,28 @@
<a href="/{{ code }}/details" class="text-decoration-none"> <a href="/{{ code }}/details" class="text-decoration-none">
<h5 class="card-title text-light">{{ playlist.name }}</h5> <h5 class="card-title text-light">{{ playlist.name }}</h5>
</a> </a>
<p class="card-text small text-secondary">{{ playlist.description }}</p> {% 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"> <div class="d-flex flex-wrap gap-2 mb-1">
{% if playlist.isOnline is not same as(null) %} {% if playlist.isOnline is not same as(null) %}
<span class="badge border border-secondary"> <span class="badge border border-secondary">
<ion-icon name="videocam-outline" class="me-1"></ion-icon>&nbsp;{{ playlist.channels|length }}&nbsp;каналов <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> </span>
{% endif %} {% endif %}
{% if playlist.groups|length > 0 %} {% if playlist.groups|length > 0 %}
<span class="badge border border-secondary"> <span class="badge border border-secondary">
<ion-icon name="folder-open-outline" class="me-1"></ion-icon>&nbsp;{{ playlist.groups|length }}&nbsp;групп <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> </span>
{% endif %} {% endif %}
{% if playlist.hasTvg %} {% if playlist.hasTvg %}
<span class="badge border border-secondary"> <span class="badge border border-secondary">
<ion-icon name="newspaper-outline" class="me-1"></ion-icon>&nbsp;ТВ-программа <ion-icon name="newspaper-outline" class="me-1"></ion-icon><span class="d-none d-xl-inline-block">&nbsp;ТВ-программа</span>
</span> </span>
{% endif %} {% endif %}
{% if playlist.hasCatchup %} {% if playlist.hasCatchup %}
<span class="badge border border-secondary"> <span class="badge border border-secondary">
<ion-icon name="play-back-outline" class="me-1"></ion-icon>&nbsp;Архив <ion-icon name="play-back-outline" class="me-1"></ion-icon><span class="d-none d-xl-inline-block">&nbsp;Архив</span>
</span> </span>
{% endif %} {% endif %}
</div> </div>

View File

@@ -12,13 +12,11 @@
<div class="card bg-dark border-secondary"> <div class="card bg-dark border-secondary">
<div class="card-body"> <div class="card-body">
<ion-icon name="warning-outline" class="display-1 text-warning mb-3"></ion-icon> <ion-icon name="warning-outline" class="display-1 text-warning mb-3"></ion-icon>
<h2 class="card-title">Плейлист не найден</h2> <h2 class="card-title">Плейлист <code>{{ code }}</code> не найден</h2>
<p class="card-text"> <p class="card-text">
Плейлист с кодом <code>{{ code }}</code> не найден в системе. Возможно, его здесь никогда не было, либо он уже был удалён.
</p> </p>
<p class="text-muted small"> <p class="text-muted small">
Возможно, его здесь никогда не было, либо он уже был удалён.
<br />
Если хочешь, чтобы здесь был плейлист, предложи его к добавлению. Если хочешь, чтобы здесь был плейлист, предложи его к добавлению.
<br /> <br />
<a href="https://iptv.axenov.dev/docs/support.html#participate">Как это сделать?</a> <a href="https://iptv.axenov.dev/docs/support.html#participate">Как это сделать?</a>