Compare commits
4 Commits
9d10f63f14
...
da2b269e44
Author | SHA1 | Date |
---|---|---|
Anthony Axenov | da2b269e44 | |
Anthony Axenov | bcadc316bc | |
Anthony Axenov | f18fb9dd7a | |
Anthony Axenov | 3204b26d8c |
|
@ -1,9 +1,27 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Flight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Абстрактный контроллер для расширения
|
||||||
|
*/
|
||||||
abstract class Controller
|
abstract class Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Перебрасывает на страницу 404 при ненайденном плейлисте
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function notFound(string $id): void
|
||||||
|
{
|
||||||
|
Flight::response()->status(404)->sendHeaders();
|
||||||
|
view('notfound', ['id' => $id]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
use App\Core\PlaylistProcessor;
|
use App\Core\PlaylistProcessor;
|
||||||
use App\Core\RedirectedPlaylist;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Flight;
|
use Flight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Контроллер домашней страницы (списка плейлистов)
|
||||||
|
*/
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var PlaylistProcessor Обработчик ini-списка
|
||||||
|
*/
|
||||||
protected PlaylistProcessor $ini;
|
protected PlaylistProcessor $ini;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->ini = new PlaylistProcessor();
|
$this->ini = new PlaylistProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* Возвращает размер одной страницы списка плейлистов
|
||||||
|
*
|
||||||
|
* @return int Указанный в конфиге размер либо 10, если он выходит за диапазоны от 5 до 100
|
||||||
*/
|
*/
|
||||||
protected function getPageSize(): int
|
protected function getPageSize(): int
|
||||||
{
|
{
|
||||||
|
@ -28,26 +38,32 @@ class HomeController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Отображает главную страницу на указанной странице списка плейлистов
|
||||||
|
*
|
||||||
|
* @param int $page
|
||||||
|
* @return void
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function index(int $page = 1)
|
public function index(int $page = 1): void
|
||||||
{
|
{
|
||||||
|
// если пришёл любой get-параметр, то считаем его как id плейлиста и перебрасываем на страницу о нём
|
||||||
if (Flight::request()->query->count() > 0) {
|
if (Flight::request()->query->count() > 0) {
|
||||||
$id = Flight::request()->query->keys()[0];
|
$id = Flight::request()->query->keys()[0];
|
||||||
Flight::redirect(base_url($id));
|
Flight::redirect(base_url($id));
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
// иначе формируем и сортируем список при необходимости, рисуем страницу
|
||||||
$per_page = $this->getPageSize();
|
$per_page = $this->getPageSize();
|
||||||
$list = $this->ini->playlists->where('redirect_id', null);
|
$list = $this->ini->playlists->where('redirect_id', null);
|
||||||
if (config('app.sort_by')) {
|
if ($sort_by = config('app.sort_by')) {
|
||||||
$list = $list->sortBy(config('app.sort_by'));
|
$list = $list->sortBy($sort_by);
|
||||||
}
|
}
|
||||||
$list = $list->forPage($page, $per_page);
|
$list = $list->forPage($page, $per_page);
|
||||||
view('list', [
|
view('list', [
|
||||||
'updated_at' => $this->ini->updatedAt(),
|
'updated_at' => $this->ini->updatedAt(),
|
||||||
'count' => $this->ini->playlists->count(),
|
'count' => $this->ini->playlists->count(),
|
||||||
'pages' => [
|
'pages' => [
|
||||||
'count' => (int)($this->ini->playlists->count() / $per_page),
|
'count' => ceil($this->ini->playlists->count() / $per_page),
|
||||||
'current' => $page,
|
'current' => $page,
|
||||||
],
|
],
|
||||||
'playlists' => $list->toArray(),
|
'playlists' => $list->toArray(),
|
||||||
|
@ -55,41 +71,13 @@ class HomeController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Отображает страницу FAQ
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function faq()
|
public function faq(): void
|
||||||
{
|
{
|
||||||
view('faq');
|
view('faq');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function details(string $id): void
|
|
||||||
{
|
|
||||||
$playlist = $this->ini->playlist($id);
|
|
||||||
if ($playlist instanceof RedirectedPlaylist) {
|
|
||||||
Flight::redirect(base_url($playlist->redirect_id . '/info'));
|
|
||||||
}
|
|
||||||
view('details', [
|
|
||||||
'id' => $id,
|
|
||||||
'playlist' => $playlist->toArray(),
|
|
||||||
'info' => $this->ini->parse($id),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function ajax(string $id): void
|
|
||||||
{
|
|
||||||
$playlist = $this->ini->playlist($id);
|
|
||||||
if ($playlist instanceof RedirectedPlaylist) {
|
|
||||||
Flight::redirect(base_url($playlist->redirect_id . '/getInfo'));
|
|
||||||
}
|
|
||||||
Flight::json([
|
|
||||||
'playlist' => $playlist->toArray(),
|
|
||||||
'info' => $this->ini->parse($id),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,102 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
use App\Core\PlaylistProcessor;
|
use App\Core\{
|
||||||
use App\Core\RedirectedPlaylist;
|
PlaylistProcessor,
|
||||||
|
RedirectedPlaylist};
|
||||||
|
use App\Exceptions\PlaylistNotFoundException;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Flight;
|
use Flight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Контроллер методов получения описания плейлистов
|
||||||
|
*/
|
||||||
class PlaylistController extends Controller
|
class PlaylistController extends Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var PlaylistProcessor Обработчик ini-списка
|
||||||
|
*/
|
||||||
protected PlaylistProcessor $ini;
|
protected PlaylistProcessor $ini;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->ini = new PlaylistProcessor();
|
$this->ini = new PlaylistProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Отправляет запрос с клиента по прямой ссылке плейлиста
|
||||||
|
*
|
||||||
|
* @param $id
|
||||||
|
* @return void
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function download($id)
|
public function download($id): void
|
||||||
{
|
{
|
||||||
$playlist = $this->ini->playlist($id);
|
try {
|
||||||
if ($playlist instanceof RedirectedPlaylist) {
|
$playlist = $this->ini->playlist($id);
|
||||||
Flight::redirect(base_url($playlist->redirect_id));
|
if ($playlist instanceof RedirectedPlaylist) {
|
||||||
die;
|
Flight::redirect(base_url($playlist->redirect_id));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
Flight::redirect($playlist->pls);
|
||||||
|
} catch (PlaylistNotFoundException) {
|
||||||
|
$this->notFound($id);
|
||||||
}
|
}
|
||||||
header('Location: ' . $playlist->pls);
|
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Отображает страницу описания плейлиста
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return void
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function details(string $id): void
|
public function details(string $id): void
|
||||||
{
|
{
|
||||||
$playlist = $this->ini->playlist($id);
|
try {
|
||||||
if ($playlist instanceof RedirectedPlaylist) {
|
$playlist = $this->ini->playlist($id);
|
||||||
Flight::redirect(base_url($playlist->redirect_id . '/details'));
|
if ($playlist instanceof RedirectedPlaylist) {
|
||||||
die;
|
Flight::redirect(base_url($playlist->redirect_id . '/details'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
view('details', [
|
||||||
|
...$playlist->toArray(),
|
||||||
|
...$this->ini->parse($id),
|
||||||
|
]);
|
||||||
|
} catch (PlaylistNotFoundException) {
|
||||||
|
$this->notFound($id);
|
||||||
}
|
}
|
||||||
view('details', [
|
|
||||||
...$playlist->toArray(),
|
|
||||||
...$this->ini->parse($id),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Возвращает JSON с описанием плейлиста
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return void
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function json(string $id): void
|
public function json(string $id): void
|
||||||
{
|
{
|
||||||
$playlist = $this->ini->playlist($id);
|
try {
|
||||||
if ($playlist instanceof RedirectedPlaylist) {
|
$playlist = $this->ini->playlist($id);
|
||||||
Flight::redirect(base_url($playlist->redirect_id . '/json'));
|
if ($playlist instanceof RedirectedPlaylist) {
|
||||||
die;
|
Flight::redirect(base_url($playlist->redirect_id . '/json'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
Flight::json([
|
||||||
|
...$playlist->toArray(),
|
||||||
|
...$this->ini->parse($id),
|
||||||
|
]);
|
||||||
|
} catch (PlaylistNotFoundException) {
|
||||||
|
Flight::response()->status(404)->sendHeaders();
|
||||||
|
Flight::json(['error' => ['message' => 'Playlist not found']]);
|
||||||
}
|
}
|
||||||
Flight::json([
|
|
||||||
...$playlist->toArray(),
|
|
||||||
...$this->ini->parse($id),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
use Illuminate\Contracts\Support\Arrayable;
|
use Illuminate\Contracts\Support\Arrayable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Базовый класс плейлиста
|
||||||
|
*/
|
||||||
abstract class BasicPlaylist implements Arrayable
|
abstract class BasicPlaylist implements Arrayable
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var string ID плейлиста
|
||||||
|
*/
|
||||||
public string $id;
|
public string $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает ссылку на плейлист в рамках проекта
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function url(): string
|
public function url(): string
|
||||||
{
|
{
|
||||||
return sprintf('%s/%s', base_url(), $this->id);
|
return sprintf('%s/%s', base_url(), $this->id);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
|
@ -15,13 +15,26 @@ use Twig\Environment;
|
||||||
use Twig\Extension\DebugExtension;
|
use Twig\Extension\DebugExtension;
|
||||||
use Twig\Loader\FilesystemLoader;
|
use Twig\Loader\FilesystemLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сборщик приложения
|
||||||
|
*/
|
||||||
final class Bootstrapper
|
final class Bootstrapper
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Загружает env-переменные
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function bootEnv(): void
|
public static function bootEnv(): void
|
||||||
{
|
{
|
||||||
(new Dotenv())->loadEnv(root_path() . '/.env');
|
(new Dotenv())->loadEnv(root_path() . '/.env');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загружает конфигурацию приложения в контейнер
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function bootSettings(): void
|
public static function bootSettings(): void
|
||||||
{
|
{
|
||||||
$settings = Arr::dot(require_once config_path('app.php'));
|
$settings = Arr::dot(require_once config_path('app.php'));
|
||||||
|
@ -31,6 +44,11 @@ final class Bootstrapper
|
||||||
Flight::set('config', $settings);
|
Flight::set('config', $settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загружает шаблонизатор и его расщирения
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function bootTwig(): void
|
public static function bootTwig(): void
|
||||||
{
|
{
|
||||||
$filesystemLoader = new FilesystemLoader(config('views.path'));
|
$filesystemLoader = new FilesystemLoader(config('views.path'));
|
||||||
|
@ -47,6 +65,11 @@ final class Bootstrapper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загружает маршруты
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function bootRoutes(): void
|
public static function bootRoutes(): void
|
||||||
{
|
{
|
||||||
Flight::route(
|
Flight::route(
|
||||||
|
|
|
@ -1,27 +1,51 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Плейлист без редиректа
|
||||||
|
*/
|
||||||
class Playlist extends BasicPlaylist
|
class Playlist extends BasicPlaylist
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null Название плейлиста
|
||||||
|
*/
|
||||||
public ?string $name;
|
public ?string $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Описание плейлиста
|
||||||
|
*/
|
||||||
public ?string $desc;
|
public ?string $desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Прямой URL до файла плейлиста на третьей стороне
|
||||||
|
*/
|
||||||
public string $pls;
|
public string $pls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Источник плейлиста
|
||||||
|
*/
|
||||||
public ?string $src;
|
public ?string $src;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Ссылка на плейлист в рамках проекта
|
||||||
|
*/
|
||||||
public string $url;
|
public string $url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \Exception
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param array $params
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct(public string $id, array $params)
|
public function __construct(public string $id, array $params)
|
||||||
{
|
{
|
||||||
empty($params['pls']) && throw new \Exception(
|
empty($params['pls']) && throw new Exception(
|
||||||
"Плейлист с ID=$id обязан иметь параметр pls или redirect"
|
"Плейлист с ID=$id обязан иметь параметр pls или redirect"
|
||||||
);
|
);
|
||||||
$this->url = base_url($id);
|
$this->url = base_url($id);
|
||||||
|
@ -31,6 +55,9 @@ class Playlist extends BasicPlaylist
|
||||||
$this->src = empty($params['src']) ? null : $params['src'];
|
$this->src = empty($params['src']) ? null : $params['src'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
public function toArray(): array
|
public function toArray(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -1,17 +1,30 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
|
use App\Exceptions\PlaylistNotFoundException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обработчик списка плейлистов
|
||||||
|
*/
|
||||||
final class PlaylistProcessor
|
final class PlaylistProcessor
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var Collection Коллекция подгруженных плейлистов
|
||||||
|
*/
|
||||||
public Collection $playlists;
|
public Collection $playlists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Дата последнего обновления списка
|
||||||
|
*/
|
||||||
protected string $updated_at;
|
protected string $updated_at;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$filepath = config_path('playlists.ini');
|
$filepath = config_path('playlists.ini');
|
||||||
|
@ -24,31 +37,60 @@ final class PlaylistProcessor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет есть ли в списке плейлист по его id
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function hasId(string $id): bool
|
public function hasId(string $id): bool
|
||||||
{
|
{
|
||||||
return in_array($id, $this->playlists->keys()->toArray());
|
return $this->playlists->keys()->contains($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает из коллекции указанный плейлист, если он существует
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return Playlist|RedirectedPlaylist
|
||||||
|
* @throws PlaylistNotFoundException
|
||||||
|
*/
|
||||||
public function playlist(string $id): Playlist|RedirectedPlaylist
|
public function playlist(string $id): Playlist|RedirectedPlaylist
|
||||||
{
|
{
|
||||||
!$this->hasId($id) && throw new \InvalidArgumentException("Плейлист с ID=$id не найден");
|
!$this->hasId($id) && throw new PlaylistNotFoundException($id);
|
||||||
return $this->playlists[$id];
|
return $this->playlists[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет доступность плейлиста на третьей стороне
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return bool
|
||||||
|
* @throws PlaylistNotFoundException
|
||||||
|
*/
|
||||||
public function check(string $id): bool
|
public function check(string $id): bool
|
||||||
{
|
{
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
curl_setopt($curl, CURLOPT_URL, $this->playlist($id)['pls']);
|
curl_setopt_array($curl, [
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
CURLOPT_URL => $this->playlist($id)->pls,
|
||||||
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
curl_setopt($curl, CURLOPT_HEADER, 0);
|
CURLOPT_TIMEOUT => 5,
|
||||||
curl_setopt($curl, CURLOPT_NOBODY, 1);
|
CURLOPT_HEADER => false,
|
||||||
|
CURLOPT_NOBODY => true,
|
||||||
|
]);
|
||||||
curl_exec($curl);
|
curl_exec($curl);
|
||||||
$code = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
|
$code = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
|
||||||
curl_close($curl);
|
curl_close($curl);
|
||||||
return $code < 400;
|
return $code < 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает содержимое плейлиста с третьей стороны
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
* @throws PlaylistNotFoundException
|
||||||
|
*/
|
||||||
protected function fetch(string $id): array
|
protected function fetch(string $id): array
|
||||||
{
|
{
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
|
@ -72,6 +114,12 @@ final class PlaylistProcessor
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает статус проверки плейлиста по коду ошибки curl
|
||||||
|
*
|
||||||
|
* @param int $curl_err_code
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
protected function guessStatus(int $curl_err_code): string
|
protected function guessStatus(int $curl_err_code): string
|
||||||
{
|
{
|
||||||
return match ($curl_err_code) {
|
return match ($curl_err_code) {
|
||||||
|
@ -82,6 +130,13 @@ final class PlaylistProcessor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Парсит полученный от третьей стороны плейлист
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array Информация о составе плейлиста
|
||||||
|
* @throws PlaylistNotFoundException
|
||||||
|
*/
|
||||||
public function parse(string $id): array
|
public function parse(string $id): array
|
||||||
{
|
{
|
||||||
$fetched = $this->fetch($id);
|
$fetched = $this->fetch($id);
|
||||||
|
@ -110,6 +165,8 @@ final class PlaylistProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Возвращает дату последнего обновления списка плейлистов
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function updatedAt(): string
|
public function updatedAt(): string
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Плейлист с редиректом
|
||||||
|
*/
|
||||||
class RedirectedPlaylist extends BasicPlaylist
|
class RedirectedPlaylist extends BasicPlaylist
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws \Exception
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $redirect_id
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
|
@ -15,6 +21,9 @@ class RedirectedPlaylist extends BasicPlaylist
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
public function toArray(): array
|
public function toArray(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class PlaylistNotFoundException extends Exception
|
||||||
|
{
|
||||||
|
public function __construct(string $pls_code)
|
||||||
|
{
|
||||||
|
parent::__construct("Плейлист $pls_code не найден!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Extensions;
|
namespace App\Extensions;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use flight\Engine;
|
use flight\Engine;
|
||||||
use flight\net\Response;
|
use flight\net\Response;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'flight' => [
|
'flight' => [
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
[1]
|
||||||
|
name = 'Bit.do от Karne4'
|
||||||
|
desc = '100+ российских и зарубежных каналов и радиостанций, а также другой контент — фильмы, сериалы, познавательные программы'
|
||||||
|
pls = 'https://seeonlinetv.ru/wp-content/uploads/iptv/iptv.m3u'
|
||||||
|
src = 'https://iptv-russia.ru/playlists/iptv-playlist/'
|
||||||
|
|
||||||
[2]
|
[2]
|
||||||
name = 'Самообновляемый IPTV плейлист 2022 (prodigtv.ru)'
|
name = 'Самообновляемый IPTV плейлист 2022 (prodigtv.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -21,12 +27,59 @@ name = 'IPTV плейлист с миксом ТВ каналов 2022 (iptv-rus
|
||||||
desc = ''
|
desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/mix.m3u'
|
pls = 'https://iptv-russia.ru/list/mix.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/mix/'
|
src = 'https://iptv-russia.ru/playlists/mix/'
|
||||||
|
[ru]
|
||||||
|
name = 'Русские'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://raw.githubusercontent.com/iptv-org/iptv/master/streams/ru.m3u'
|
||||||
|
src = 'https://github.com/iptv-org/iptv'
|
||||||
|
|
||||||
[p4]
|
[ru2]
|
||||||
name = 'IPTV плейлист на июль 2020 (iptvm3u.ru)'
|
name = 'Русские 2'
|
||||||
desc = 'Плейлист содержит 1200+ ТВ каналов всех категорий (музыка, спорт, детские, образовательные, взрослые). Так же в файле есть каналы Украины, Белоруссии, Молдовы. Для удобства каналы других стран расположены в низу списка.'
|
desc = ''
|
||||||
pls = 'https://iptvm3u.ru/0720.m3u'
|
pls = 'https://raw.githubusercontent.com/iptv-org/iptv/master/streams/ru_okkotv.m3u'
|
||||||
src = 'https://iptvm3u.ru/iptv-plejlist-na-ijul-2/'
|
src = 'https://github.com/iptv-org/iptv'
|
||||||
|
|
||||||
|
[ru3]
|
||||||
|
name = 'Русские 3'
|
||||||
|
desc =
|
||||||
|
pls = 'https://getsapp.ru/IPTV/Auto_IPTV.m3u'
|
||||||
|
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
||||||
|
|
||||||
|
[ru6]
|
||||||
|
name = 'Русские 6'
|
||||||
|
desc =
|
||||||
|
pls = 'http://iptv.ktkru.ru/playlist.m3u'
|
||||||
|
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
||||||
|
|
||||||
|
[ru7]
|
||||||
|
name = 'IPTV плейлист с ТВ каналами России 2022 (iptv-russia.ru)'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://iptv-russia.ru/list/ru-all.m3u'
|
||||||
|
src = 'https://iptv-russia.ru/playlists/ru-all/'
|
||||||
|
|
||||||
|
[rf]
|
||||||
|
name='Российские'
|
||||||
|
desc=''
|
||||||
|
pls = "https://m3url.ru/880750.m3u"
|
||||||
|
src= 'https://satellitetvforum.info/viewtopic.php?p=264227#p264227'
|
||||||
|
|
||||||
|
[kid1]
|
||||||
|
name = '30 каналов для детей и мультфильмами (prodigtv.ru)'
|
||||||
|
desc = 'Телеканалы с прямой трансляцией детских фильмов, мультфильмов и спектаклей. Среди них: Карусель, Disney, Артек, Бумеранг, Детское Кино, Kinder TV, Алладин, Радость моя, Смайлик ТВ, Ginger HD, Детский мир и другие'
|
||||||
|
pls = 'https://prodigtv.ru/play/kids.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/dlya-detey'
|
||||||
|
|
||||||
|
[kid2]
|
||||||
|
name = '650 мультфильмов для детей (prodigtv.ru)'
|
||||||
|
desc = 'Избранные добрые мультики советского и российского кинематографа для детей всех возрастов. '
|
||||||
|
pls = 'https://prodigtv.ru/play/mult.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/dlya-detey'
|
||||||
|
|
||||||
|
[kid3]
|
||||||
|
name = 'Каналы и мультфильмы вместе (prodigtv.ru)'
|
||||||
|
desc = 'Плейлист, объединяющий два предыдущих'
|
||||||
|
pls = 'https://prodigtv.ru/play/tvkids.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/dlya-detey'
|
||||||
|
|
||||||
[p5]
|
[p5]
|
||||||
name = 'Плейлист 2020 от iptv-playlisty.ru'
|
name = 'Плейлист 2020 от iptv-playlisty.ru'
|
||||||
|
@ -34,18 +87,6 @@ desc = 'Трансляции для детей и подростков. Сери
|
||||||
pls = 'https://iptv-playlisty.ru/wp-content/uploads/m3u/2020.m3u'
|
pls = 'https://iptv-playlisty.ru/wp-content/uploads/m3u/2020.m3u'
|
||||||
src = 'https://iptv-playlisty.ru/collection/samyj-svezheobnovlennyj-plejlist-iptv-na-2020-god/'
|
src = 'https://iptv-playlisty.ru/collection/samyj-svezheobnovlennyj-plejlist-iptv-na-2020-god/'
|
||||||
|
|
||||||
[kid1]
|
|
||||||
name = 'Детский IPTV «Kids»'
|
|
||||||
desc = ''
|
|
||||||
pls = 'https://webhalpme.ru/kids.m3u'
|
|
||||||
src = 'https://webhalpme.ru/samoobnovljaemye-plejlisty-iptv-2019/'
|
|
||||||
|
|
||||||
[kid2]
|
|
||||||
name = 'Плейлист детских каналов iptvmaster.ru'
|
|
||||||
desc = '02.08.2020 Среди детских каналов есть и отечественные, и зарубежные, большинство из них в HD.'
|
|
||||||
pls = 'https://iptvmaster.ru/kids-all.m3u'
|
|
||||||
src = 'https://iptvmaster.ru/detskie-kanaly-playlist/'
|
|
||||||
|
|
||||||
[np]
|
[np]
|
||||||
name = 'Плейлист newplay (iptv-playlisty.ru)'
|
name = 'Плейлист newplay (iptv-playlisty.ru)'
|
||||||
desc = 'Общефедеральные. Каналы фильмов. Все на русском. Имеются с зарубежными лентами. Спортивные. Как трансляции, так и кино данной тематики. Детские. Мультфильмы и передачи.'
|
desc = 'Общефедеральные. Каналы фильмов. Все на русском. Имеются с зарубежными лентами. Спортивные. Как трансляции, так и кино данной тематики. Детские. Мультфильмы и передачи.'
|
||||||
|
@ -94,23 +135,29 @@ desc =
|
||||||
pls = 'http://bluecrabstv.do.am/serial.m3u'
|
pls = 'http://bluecrabstv.do.am/serial.m3u'
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
||||||
|
|
||||||
|
[kino1]
|
||||||
|
name = '2000 фильмов - Бесплатный IPTV плейлист с фильмами (prodigtv.ru)'
|
||||||
|
desc = 'Боевики, комедии, мелодрамы, мистика, криминал, приключения, триллеры, фантастика, ужасы. Много потоков с качеством Full HD'
|
||||||
|
pls = 'https://prodigtv.ru/play/film1.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/filmy'
|
||||||
|
|
||||||
[kino2]
|
[kino2]
|
||||||
name = 'Фильмы 2'
|
name = '438 фильмов - Бесплатный IPTV плейлист с фильмами (prodigtv.ru)'
|
||||||
desc =
|
desc = 'Новинки 2020-2021 года (сериалы, кино), лучшие мировые шедевры XX-XXI века'
|
||||||
pls = 'http://iptvm3u.ru/500newFilms.m3u'
|
pls = 'https://prodigtv.ru/play/film2.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://prodigtv.ru/iptv/playlist/filmy'
|
||||||
|
|
||||||
[kino3]
|
[kino3]
|
||||||
name = 'Фильмы 3'
|
name = '670 фильмов - Бесплатный IPTV плейлист с фильмами (prodigtv.ru)'
|
||||||
desc =
|
desc = 'Классика советского и российского кинематографа, избранные зарубежные новинки'
|
||||||
pls = 'http://iptvm3u.ru/film1.m3u'
|
pls = 'https://prodigtv.ru/play/film3.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://prodigtv.ru/iptv/playlist/filmy'
|
||||||
|
|
||||||
[kino4]
|
[kino4]
|
||||||
name = 'Фильмы 4'
|
name = '980 фильмов - Бесплатный IPTV плейлист с фильмами (prodigtv.ru)'
|
||||||
desc =
|
desc = 'Лучшие российские и зарубежные картины XX века. Много топовых боевиков и культовых кинолент'
|
||||||
pls = 'http://iptvm3u.ru/film4.m3u'
|
pls = 'https://prodigtv.ru/play/film4.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://prodigtv.ru/iptv/playlist/filmy'
|
||||||
|
|
||||||
[kino5]
|
[kino5]
|
||||||
name = 'Фильмы 5'
|
name = 'Фильмы 5'
|
||||||
|
@ -124,41 +171,11 @@ desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/cinematic.m3u'
|
pls = 'https://iptv-russia.ru/list/cinematic.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/cinematic/'
|
src = 'https://iptv-russia.ru/playlists/cinematic/'
|
||||||
|
|
||||||
[ru1]
|
[kino7]
|
||||||
name = 'Русские 1'
|
name = '210 киноканалов - Бесплатный IPTV плейлист с фильмами (prodigtv.ru)'
|
||||||
desc =
|
desc = 'Подборка популярных каналов с кинофильмами в качестве от HD до 4К'
|
||||||
pls = 'https://webhalpme.ru/RussiaIPTV.m3u'
|
pls = 'https://prodigtv.ru/play/film5.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://prodigtv.ru/iptv/playlist/filmy'
|
||||||
|
|
||||||
[ru3]
|
|
||||||
name = 'Русские 3'
|
|
||||||
desc =
|
|
||||||
pls = 'https://getsapp.ru/IPTV/Auto_IPTV.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[ru4]
|
|
||||||
name = 'Русские 4'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/list2511.m3u8'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[ru5]
|
|
||||||
name = 'Русские 5'
|
|
||||||
desc =
|
|
||||||
pls = 'https://avdmono.do.am/film/natgeo.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[ru6]
|
|
||||||
name = 'Русские 6'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptv.ktkru.ru/playlist.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[ru7]
|
|
||||||
name = 'IPTV плейлист с ТВ каналами России 2022 (iptv-russia.ru)'
|
|
||||||
desc = ''
|
|
||||||
pls = 'https://iptv-russia.ru/list/ru-all.m3u'
|
|
||||||
src = 'https://iptv-russia.ru/playlists/ru-all/'
|
|
||||||
|
|
||||||
[reg]
|
[reg]
|
||||||
name = 'IPTV Плейлист — Региональные каналы России (iptv-russia.ru)'
|
name = 'IPTV Плейлист — Региональные каналы России (iptv-russia.ru)'
|
||||||
|
@ -166,6 +183,12 @@ desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/ru-regional.m3u'
|
pls = 'https://iptv-russia.ru/list/ru-regional.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/ru-regional/'
|
src = 'https://iptv-russia.ru/playlists/ru-regional/'
|
||||||
|
|
||||||
|
[ua1]
|
||||||
|
name = 'IPTV плейлист с украинскими ТВ-каналами 2022 (prodigtv.ru)'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://prodigtv.ru/play/ua.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/ukraina'
|
||||||
|
|
||||||
[ua2]
|
[ua2]
|
||||||
name = 'Украинские 2'
|
name = 'Украинские 2'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -190,6 +213,12 @@ desc = 'Украинские каналы и фильмы'
|
||||||
pls = 'https://tva.org.ua/ip/sam/avto-iptv-tva.m3u'
|
pls = 'https://tva.org.ua/ip/sam/avto-iptv-tva.m3u'
|
||||||
src = 'https://tva.org.ua/avto-iptv-playlist-m3u-2022-tva.html'
|
src = 'https://tva.org.ua/avto-iptv-playlist-m3u-2022-tva.html'
|
||||||
|
|
||||||
|
[ua6]
|
||||||
|
name = 'Украина'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://raw.githubusercontent.com/iptv-org/iptv/master/streams/ua.m3u'
|
||||||
|
src = 'https://github.com/iptv-org/iptv'
|
||||||
|
|
||||||
[by]
|
[by]
|
||||||
name = 'IPTV плейлист с ТВ каналами Беларуси 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист с ТВ каналами Беларуси 2022 (iptv-russia.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -208,12 +237,18 @@ desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/uz-all.m3u'
|
pls = 'https://iptv-russia.ru/list/uz-all.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/uz-all/'
|
src = 'https://iptv-russia.ru/playlists/uz-all/'
|
||||||
|
|
||||||
[uz]
|
[kz]
|
||||||
name = 'IPTV плейлист с ТВ каналами Казахстана 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист с ТВ каналами Казахстана 2022 (iptv-russia.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/kz-all.m3u'
|
pls = 'https://iptv-russia.ru/list/kz-all.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/kz-all/'
|
src = 'https://iptv-russia.ru/playlists/kz-all/'
|
||||||
|
|
||||||
|
[kz2]
|
||||||
|
name = 'Казахстан'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://raw.githubusercontent.com/iptv-org/iptv/master/streams/kz.m3u'
|
||||||
|
src = 'https://github.com/iptv-org/iptv'
|
||||||
|
|
||||||
[tr]
|
[tr]
|
||||||
name = 'IPTV плейлист с ТВ каналами Турции и Азербайджана 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист с ТВ каналами Турции и Азербайджана 2022 (iptv-russia.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -238,47 +273,11 @@ desc =
|
||||||
pls = 'https://iptvmaster.ru/kids.m3u'
|
pls = 'https://iptvmaster.ru/kids.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
||||||
|
|
||||||
[m3]
|
|
||||||
name = 'Мультфильмы 3'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvmaster.ru/multfilm.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[m4]
|
|
||||||
name = 'Мультфильмы 4'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvmaster.ru/kids-all.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[m6]
|
|
||||||
name = 'Мультфильмы 6'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptvm3u.ru/film4.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
|
||||||
|
|
||||||
[m7]
|
|
||||||
name = 'Мультфильмы 7'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptvm3u.ru/film2.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
|
||||||
|
|
||||||
[m8]
|
|
||||||
name = 'Мультфильмы 8'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptvm3u.ru/film1.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
|
||||||
|
|
||||||
[m9]
|
|
||||||
name = 'Мультфильмы 9'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptvm3u.ru/500newFilms.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
|
||||||
|
|
||||||
[sci]
|
[sci]
|
||||||
name = 'Познавательные'
|
name = 'Познавательные'
|
||||||
desc = ''
|
desc = '40+ российских и зарубежных образовательно-познавательных и научно-популярных каналов'
|
||||||
pls = 'https://iptvmaster.ru/poznavatelnoe.m3u'
|
pls = 'https://iptvmaster.ru/poznavatelnoe.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://iptv-russia.ru/playlists/iptv-playlist/'
|
||||||
|
|
||||||
[sci2]
|
[sci2]
|
||||||
name = 'IPTV плейлист с познавательными ТВ каналами 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист с познавательными ТВ каналами 2022 (iptv-russia.ru)'
|
||||||
|
@ -292,6 +291,18 @@ desc = ''
|
||||||
pls = 'https://iptv-russia.ru/list/sport-all.m3u'
|
pls = 'https://iptv-russia.ru/list/sport-all.m3u'
|
||||||
src = 'https://iptv-russia.ru/playlists/sports-all/'
|
src = 'https://iptv-russia.ru/playlists/sports-all/'
|
||||||
|
|
||||||
|
[sp2]
|
||||||
|
name = 'Бесплатный IPTV плейлист со спортивными каналами (prodigtv.ru)'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://prodigtv.ru/play/sport.m3u'
|
||||||
|
src = 'https://prodigtv.ru/iptv/playlist/sport'
|
||||||
|
|
||||||
|
[sp3]
|
||||||
|
name = 'Sport от IPTVmaster.ru'
|
||||||
|
desc = '50+ российских и зарубежных спортивных каналов, где показывают трансляции матчей и соревнований, программы об известных спортсменах, командах и не только'
|
||||||
|
pls = 'https://iptvmaster.ru/sport.m3u'
|
||||||
|
src = 'https://iptv-russia.ru/playlists/iptv-playlist/'
|
||||||
|
|
||||||
[cam]
|
[cam]
|
||||||
name = 'IPTV плейлист с вебкамерами России и мира 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист с вебкамерами России и мира 2022 (iptv-russia.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -316,60 +327,6 @@ desc =
|
||||||
pls = 'https://iptvmaster.ru/radio.m3u'
|
pls = 'https://iptvmaster.ru/radio.m3u'
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
||||||
|
|
||||||
[sng1]
|
|
||||||
name = 'Каналы СНГ 1'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/iptv1218.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng2]
|
|
||||||
name = 'Каналы СНГ 2'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/0119.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng3]
|
|
||||||
name = 'Каналы СНГ 3'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/0219.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng4]
|
|
||||||
name = 'Каналы СНГ 4'
|
|
||||||
desc =
|
|
||||||
pls = 'http://iptvm3u.ru/iptv082018.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng5]
|
|
||||||
name = 'Каналы СНГ 5'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/0919.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng6]
|
|
||||||
name = 'Каналы СНГ 6'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/0819.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng7]
|
|
||||||
name = 'Каналы СНГ 7'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/1019.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng8]
|
|
||||||
name = 'Каналы СНГ 8'
|
|
||||||
desc =
|
|
||||||
pls = 'https://iptvm3u.ru/1119.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng10]
|
|
||||||
name = 'Каналы СНГ 10'
|
|
||||||
desc =
|
|
||||||
pls = 'https://webhalpme.ru/donwhm.m3u'
|
|
||||||
src = 'https://iptvsensei.ru/novye-samoobnovlyaemye-plejlisty'
|
|
||||||
|
|
||||||
[sng11]
|
[sng11]
|
||||||
name = 'Каналы СНГ 11'
|
name = 'Каналы СНГ 11'
|
||||||
desc =
|
desc =
|
||||||
|
@ -394,6 +351,12 @@ desc =
|
||||||
pls = 'http://gorod.tv/iptv.m3u'
|
pls = 'http://gorod.tv/iptv.m3u'
|
||||||
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
src = 'https://iptvsensei.ru/samoobnovlyayemyye-pleylisty-iptv'
|
||||||
|
|
||||||
|
[x]
|
||||||
|
name = '18+ от от IPTVmaster.ru'
|
||||||
|
desc = '40+ фильмов и передач для взрослых, в том числе в жанре “Эротика“. Список постоянно обновляется.'
|
||||||
|
pls = 'https://iptvmaster.ru/18.m3u'
|
||||||
|
src = 'https://iptv-russia.ru/playlists/iptv-playlist/'
|
||||||
|
|
||||||
[x2]
|
[x2]
|
||||||
name = 'IPTV плейлист для взрослых 2022 (iptv-russia.ru)'
|
name = 'IPTV плейлист для взрослых 2022 (iptv-russia.ru)'
|
||||||
desc = ''
|
desc = ''
|
||||||
|
@ -406,12 +369,6 @@ desc = ''
|
||||||
pls = 'https://www.digitaltv.ru/upload/iblock/034/tvlist.m3u'
|
pls = 'https://www.digitaltv.ru/upload/iblock/034/tvlist.m3u'
|
||||||
src = 'https://www.digitaltv.ru/news/iptv_pleylisty.html'
|
src = 'https://www.digitaltv.ru/news/iptv_pleylisty.html'
|
||||||
|
|
||||||
[rf]
|
|
||||||
name='Российские'
|
|
||||||
desc=''
|
|
||||||
pls = "https://m3url.ru/880750.m3u"
|
|
||||||
src= 'https://satellitetvforum.info/viewtopic.php?p=264227#p264227'
|
|
||||||
|
|
||||||
[al]
|
[al]
|
||||||
name='Каналы Албании'
|
name='Каналы Албании'
|
||||||
desc=''
|
desc=''
|
||||||
|
@ -424,6 +381,12 @@ desc=''
|
||||||
pls = 'https://m3url.ru/Azerbaijan_1.iptvcat.com.m3u8'
|
pls = 'https://m3url.ru/Azerbaijan_1.iptvcat.com.m3u8'
|
||||||
src= 'https://satellitetvforum.info/viewtopic.php?p=264227#p264227'
|
src= 'https://satellitetvforum.info/viewtopic.php?p=264227#p264227'
|
||||||
|
|
||||||
|
[az2]
|
||||||
|
name='Каналы Азербайджана'
|
||||||
|
desc = ''
|
||||||
|
pls = 'https://raw.githubusercontent.com/iptv-org/iptv/master/streams/az.m3u'
|
||||||
|
src = 'https://github.com/iptv-org/iptv'
|
||||||
|
|
||||||
[po]
|
[po]
|
||||||
name='Каналы Польши'
|
name='Каналы Польши'
|
||||||
desc=''
|
desc=''
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use App\Core\Bootstrapper;
|
use App\Core\Bootstrapper;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "layouts/default.twig" %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
<h2>Плейлист не найден</h2>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p>
|
||||||
|
Плейлист {{ id }} не найден
|
||||||
|
</p>
|
||||||
|
<a class="navbar-brand" href="{{ base_url() }}" title="На главную">
|
||||||
|
Перейти к списку
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue