Команды /help, /stats и /links + конфиг для зеркала
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
# config/app.php
|
# config/app.php
|
||||||
APP_URL="http://localhost:8080"
|
APP_URL="http://localhost:8080"
|
||||||
|
APP_URL_MIRROR="https://m3u.su/"
|
||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
APP_ENV="prod"
|
APP_ENV="prod"
|
||||||
APP_TITLE="IPTV Плейлисты"
|
APP_TITLE="IPTV Плейлисты"
|
||||||
|
|||||||
@@ -64,6 +64,7 @@
|
|||||||
* [Bootstrap v5.2](https://getbootstrap.com/docs/5.2/getting-started/introduction/)
|
* [Bootstrap v5.2](https://getbootstrap.com/docs/5.2/getting-started/introduction/)
|
||||||
* [Ionicons](https://ionic.io/ionicons)
|
* [Ionicons](https://ionic.io/ionicons)
|
||||||
* [List.js](https://listjs.com)
|
* [List.js](https://listjs.com)
|
||||||
|
* [telegram-bot/api](https://packagist.org/packages/telegram-bot/api)
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
180
app/Core/Bot.php
180
app/Core/Bot.php
@@ -67,13 +67,19 @@ class Bot
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
|
* @throws \TelegramBot\Api\Exception
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function process(): bool
|
public function process(): bool
|
||||||
{
|
{
|
||||||
|
$this->bot->sendChatAction($this->update->getMessage()->getChat()->getId(), 'typing');
|
||||||
$commandText = $this->getBotCommandText();
|
$commandText = $this->getBotCommandText();
|
||||||
return match ($commandText) {
|
return match (true) {
|
||||||
'/list', '/list@iptv_aggregator_bot' => $this->processListCommand(),
|
str_starts_with($commandText, '/list') => $this->processListCommand(),
|
||||||
'/info', '/info@iptv_aggregator_bot' => $this->processInfoCommand(),
|
str_starts_with($commandText, '/info') => $this->processInfoCommand(),
|
||||||
|
str_starts_with($commandText, '/help') => $this->processHelpCommand(),
|
||||||
|
str_starts_with($commandText, '/links') => $this->processLinksCommand(),
|
||||||
|
str_starts_with($commandText, '/stats') => $this->processStatsCommand(),
|
||||||
default => true,
|
default => true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -109,11 +115,11 @@ class Bot
|
|||||||
[
|
[
|
||||||
[
|
[
|
||||||
'text' => 'Список на сайте',
|
'text' => 'Список на сайте',
|
||||||
'url' => "https://iptv.axenov.dev/",
|
'url' => base_url(),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'text' => 'FAQ',
|
'text' => 'FAQ',
|
||||||
'url' => 'https://iptv.axenov.dev/faq',
|
'url' => base_url('faq'),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -151,7 +157,7 @@ class Bot
|
|||||||
};
|
};
|
||||||
|
|
||||||
in_array('adult', $pls['tags']) && $statusEmoji .= "🔞";
|
in_array('adult', $pls['tags']) && $statusEmoji .= "🔞";
|
||||||
$replyText[] = $statusEmoji . ' [' . $this->escape($pls['name']) . "](https://m3u.su/$code/details)\n";
|
$replyText[] = $statusEmoji . ' [' . $this->escape($pls['name']) . '](' . base_url("$code/details") . ")\n";
|
||||||
empty($pls['description']) || $replyText[] = $this->escape($pls['description']) . "\n";
|
empty($pls['description']) || $replyText[] = $this->escape($pls['description']) . "\n";
|
||||||
|
|
||||||
if ($pls['isOnline'] === null) {
|
if ($pls['isOnline'] === null) {
|
||||||
@@ -161,14 +167,16 @@ class Bot
|
|||||||
$checkedAt = DateTimeImmutable::createFromTimestamp($pls['checkedAt']);
|
$checkedAt = DateTimeImmutable::createFromTimestamp($pls['checkedAt']);
|
||||||
$minutes = $checkedAt->diff($now)->i;
|
$minutes = $checkedAt->diff($now)->i;
|
||||||
$replyText[] = "⏲️ *Проверка:* " . ($minutes > 1 ? "$minutes мин\. назад" : "только что");
|
$replyText[] = "⏲️ *Проверка:* " . ($minutes > 1 ? "$minutes мин\. назад" : "только что");
|
||||||
$replyText[] = "📺 *Каналов:* " . count($pls['channels']) .
|
|
||||||
|
if ($pls['isOnline'] === true) {
|
||||||
|
$replyText[] = "📺 *Каналов:* " . count($pls['channels'] ?? []) .
|
||||||
' \(онлайн ' . $pls['onlineCount'] . ', оффлайн ' . $pls['offlineCount'] . "\)";
|
' \(онлайн ' . $pls['onlineCount'] . ', оффлайн ' . $pls['offlineCount'] . "\)";
|
||||||
$replyText[] = "⏪ *Перемотка:* " . ($pls['hasCatchup'] === true ? '*есть*' : 'нет');
|
$replyText[] = "⏪ *Перемотка:* " . ($pls['hasCatchup'] === true ? '*есть*' : 'нет');
|
||||||
$replyText[] = "🗞️ *Телепрограмма:* " . ($pls['hasTvg'] === true ? '*есть*' : 'нет');
|
$replyText[] = "🗞️ *Телепрограмма:* " . ($pls['hasTvg'] === true ? '*есть*' : 'нет');
|
||||||
|
|
||||||
if (count($pls['groups'] ?? []) > 0) {
|
if (count($pls['groups'] ?? []) > 0) {
|
||||||
$groups = array_map(fn (array $group) => $this->escape($group['name']), $pls['groups']);
|
$groups = array_map(fn (array $group) => $this->escape($group['name']), $pls['groups']);
|
||||||
$replyText[] = "\n🗂️ *Группы* \(" . count($pls['groups']) . "\):\n**>\- " .
|
$replyText[] = "\n🗂️ *Группы* \(" . count($pls['groups'] ?? []) . "\):\n**>\- " .
|
||||||
implode("\n>\- ", $groups) . '||';
|
implode("\n>\- ", $groups) . '||';
|
||||||
} else {
|
} else {
|
||||||
$replyText[] = "🗂️ *Группы:* нет";
|
$replyText[] = "🗂️ *Группы:* нет";
|
||||||
@@ -180,13 +188,18 @@ class Bot
|
|||||||
} else {
|
} else {
|
||||||
$replyText[] = "🏷️ *Теги:* нет";
|
$replyText[] = "🏷️ *Теги:* нет";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$replyText[] = "❌ *Ошибка проверки:*\n**>" . $this->escape($pls['content']) . "||\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$replyText[] = "🔗 *Ссылка для ТВ:* \(скопируй подходящую\)";
|
$replyText[] = "🔗 *Ссылка для ТВ:* \(скопируй подходящую\)";
|
||||||
$replyText[] = "\- `https://m3u.su/$code`";
|
if (config('app.mirror_url')) {
|
||||||
$replyText[] = "\- `https://m3u.su/$code.m3u`";
|
$replyText[] = '\- `' . mirror_url("$code") . '`';
|
||||||
$replyText[] = "\- `https://iptv.axenov.dev/$code`";
|
$replyText[] = '\- `' . mirror_url("$code.m3u") . '`';
|
||||||
$replyText[] = "\- `https://iptv.axenov.dev/$code.m3u`\n";
|
}
|
||||||
|
$replyText[] = '\- `' . base_url("$code") . '`';
|
||||||
|
$replyText[] = '\- `' . base_url("$code.m3u") . "`\n";
|
||||||
|
|
||||||
return $this->reply(
|
return $this->reply(
|
||||||
implode("\n", $replyText),
|
implode("\n", $replyText),
|
||||||
@@ -195,11 +208,11 @@ class Bot
|
|||||||
[
|
[
|
||||||
[
|
[
|
||||||
'text' => is_null($pls['isOnline']) ? 'Подробности' : 'Список каналов',
|
'text' => is_null($pls['isOnline']) ? 'Подробности' : 'Список каналов',
|
||||||
'url' => "https://iptv.axenov.dev/$code/details",
|
'url' => base_url("$code/details"),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'text' => 'FAQ',
|
'text' => 'FAQ',
|
||||||
'url' => 'https://iptv.axenov.dev/faq',
|
'url' => base_url('faq'),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -207,6 +220,145 @@ class Bot
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает команду /help
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function processHelpCommand(): bool
|
||||||
|
{
|
||||||
|
$replyText[] = 'Бот предоставляет короткую сводку о плейлистах, которые видны на сайте ' .
|
||||||
|
$this->escape(base_url()) . '\.';
|
||||||
|
$replyText[] = 'Плейлисты проверяются сервером автоматически\.';
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = 'Команды бота:';
|
||||||
|
$replyText[] = '`/list` \- список кодов всех плейлистов;';
|
||||||
|
$replyText[] = '`/info <код>` \- информация о плейлисте с указанным кодом;';
|
||||||
|
$replyText[] = '`/help` \- данная справка\.';
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = 'Статусы плейлистов:';
|
||||||
|
$replyText[] = '🟢 \- онлайн';
|
||||||
|
$replyText[] = '🔴 \- оффлайн';
|
||||||
|
$replyText[] = '⚪ \- не проверялось';
|
||||||
|
$replyText[] = '🔞 \- есть каналы для взрослых';
|
||||||
|
|
||||||
|
return $this->reply(implode("\n", $replyText));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает команду /links
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function processLinksCommand(): bool
|
||||||
|
{
|
||||||
|
$replyText[] = '*Ресурсы и страницы*';
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = '🌏 Сайт: ' . $this->escape(base_url());
|
||||||
|
config('app.mirror_url') && $replyText[] = '🪞 Зеркало: ' . $this->escape(mirror_url());
|
||||||
|
$replyText[] = '👩💻 Исходный код: ' . $this->escape('https://git.axenov.dev/IPTV');
|
||||||
|
$replyText[] = '✈️ Telegram\-канал: @iptv\_aggregator';
|
||||||
|
$replyText[] = '✈️ Обсуждение: @iptv\_aggregator\_chat';
|
||||||
|
$replyText[] = '📚 Доп\. сведения:';
|
||||||
|
$replyText[] = '\- ' . $this->escape('https://git.axenov.dev/IPTV/.profile');
|
||||||
|
$replyText[] = '\- ' . $this->escape(base_url('faq'));
|
||||||
|
|
||||||
|
return $this->reply(implode("\n", $replyText));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает команду /stats
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function processStatsCommand(): bool
|
||||||
|
{
|
||||||
|
$allChannels = [];
|
||||||
|
foreach (ini()->getPlaylists() as $pls) {
|
||||||
|
$allChannels = array_merge($allChannels, $pls['channels'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
$onlinePls = array_filter(
|
||||||
|
ini()->getPlaylists(),
|
||||||
|
static fn (array $pls) => $pls['isOnline'] === true,
|
||||||
|
);
|
||||||
|
|
||||||
|
$offlinePls = array_filter(
|
||||||
|
ini()->getPlaylists(),
|
||||||
|
static fn (array $pls) => $pls['isOnline'] === false,
|
||||||
|
);
|
||||||
|
|
||||||
|
$unknownPls = array_filter(
|
||||||
|
ini()->getPlaylists(),
|
||||||
|
static fn (array $pls) => $pls['isOnline'] === null,
|
||||||
|
);
|
||||||
|
|
||||||
|
$adultPls = array_filter(
|
||||||
|
$onlinePls,
|
||||||
|
static fn (array $pls) => in_array('adult', $pls['tags']),
|
||||||
|
);
|
||||||
|
|
||||||
|
$catchupPls = array_filter(
|
||||||
|
$onlinePls,
|
||||||
|
static fn (array $pls) => $pls['hasCatchup'] === true,
|
||||||
|
);
|
||||||
|
|
||||||
|
$tvgPls = array_filter(
|
||||||
|
$onlinePls,
|
||||||
|
static fn (array $pls) => $pls['hasTvg'] === true,
|
||||||
|
);
|
||||||
|
|
||||||
|
$grouppedPls = array_filter(
|
||||||
|
$onlinePls,
|
||||||
|
static fn (array $pls) => count($pls['groups'] ?? []) > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
$onlineCh = $offlineCh = $adultCh = [];
|
||||||
|
foreach ($onlinePls as $pls) {
|
||||||
|
$tmpOnline = array_filter(
|
||||||
|
$pls['channels'] ?? [],
|
||||||
|
static fn (array $ch) => $ch['isOnline'] === true,
|
||||||
|
);
|
||||||
|
|
||||||
|
$tmpOffline = array_filter(
|
||||||
|
$pls['channels'] ?? [],
|
||||||
|
static fn (array $ch) => $ch['isOnline'] === false,
|
||||||
|
);
|
||||||
|
|
||||||
|
$tmpAdult = array_filter(
|
||||||
|
$pls['channels'] ?? [],
|
||||||
|
static fn (array $ch) => in_array('adult', $ch['tags']),
|
||||||
|
);
|
||||||
|
|
||||||
|
$onlineCh = array_merge($onlineCh, $tmpOnline);
|
||||||
|
$offlineCh = array_merge($offlineCh, $tmpOffline);
|
||||||
|
$adultCh = array_merge($adultCh, $tmpAdult);
|
||||||
|
}
|
||||||
|
|
||||||
|
$replyText[] = '📊 *Статистика*';
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = '*Список изменён:* ' . $this->escape(ini()->updatedAt());
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = '*Плейлистов:* ' . count(ini()->getPlaylists());
|
||||||
|
$replyText[] = '🟢 Онлайн \- ' . count($onlinePls);
|
||||||
|
$replyText[] = '🔴 Оффлайн \- ' . count($offlinePls);
|
||||||
|
$replyText[] = '⚪ В очереди \- ' . count($unknownPls);
|
||||||
|
$replyText[] = '🔞 Для взрослых \- ' . count($adultPls);
|
||||||
|
$replyText[] = '⏪ С перемоткой \- ' . count($catchupPls);
|
||||||
|
$replyText[] = '🗞️ С телепрограммой \- ' . count($tvgPls);
|
||||||
|
$replyText[] = '🗂️ С группировкой каналов \- ' . count($grouppedPls);
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = '*Каналов:* ' . count($allChannels);
|
||||||
|
$replyText[] = '🟢 Онлайн \- ' . count($onlineCh);
|
||||||
|
$replyText[] = '🔴 Оффлайн \- ' . count($offlineCh);
|
||||||
|
$replyText[] = '🔞 Для взрослых \- ' . count($adultCh);
|
||||||
|
$replyText[] = '';
|
||||||
|
$replyText[] = '';
|
||||||
|
|
||||||
|
return $this->reply(implode("\n", $replyText));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сверяет секретный заголовок с заданным в конфиге
|
* Сверяет секретный заголовок с заданным в конфиге
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -52,7 +52,18 @@ function cache_path(string $path = ''): string
|
|||||||
*/
|
*/
|
||||||
function base_url(string $route = ''): string
|
function base_url(string $route = ''): string
|
||||||
{
|
{
|
||||||
return rtrim(sprintf('%s/%s', env('APP_URL'), $route), '/');
|
return rtrim(sprintf('%s/%s', config('app.base_url'), $route), '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns mirror URL
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function mirror_url(string $route = ''): string
|
||||||
|
{
|
||||||
|
return rtrim(sprintf('%s/%s', config('app.mirror_url'), $route), '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'base_url' => env('APP_URL', 'http://localhost:8080'),
|
'base_url' => rtrim(trim(env('APP_URL', 'http://localhost:8080')), '/'),
|
||||||
|
'mirror_url' => rtrim(trim(env('APP_URL_MIRROR') ?? '', '/')),
|
||||||
'debug' => bool(env('APP_DEBUG', false)),
|
'debug' => bool(env('APP_DEBUG', false)),
|
||||||
'env' => env('APP_ENV', env('IPTV_ENV', 'prod')),
|
'env' => env('APP_ENV', env('IPTV_ENV', 'prod')),
|
||||||
'title' => 'IPTV Плейлисты',
|
'title' => 'IPTV Плейлисты',
|
||||||
|
|||||||
Reference in New Issue
Block a user