Пару месяцев назад мне надоело ежедневно тыкать сайт стопкоронавирус.рф с целью узнать статистику числа зараженных ковидом в моём городе. Так как по долгу службы я часто сижу в рабочем Discord-е, решил написать написать небольшое приложение для отправки статистики числа новых случаев в канал Discord сервера, который использую я и мои коллеги.
Реализация оказалась весьма тривиальна.
Первое, что нам понадобится, это доступ к самому дискорд серверу. Создадим новый канал под названием «Коронавирус». В настройках канала закрываем доступ к постингу сообщений, т.к. канал будет чисто информативный.

Далее опять же в настройках создаём вебхук с названием covid-bot:

На этом подготовительная часть в плане настроек Discord сервера завершена.
Переходим к кодингу.
Решение будет работать на основе данных с сайта стопкоронавирус.рф
Допустим, нам нужна статистика по городу Санкт-Петербург. На карте оперативной информации тыкаем на Питер и в отладчике замечаем GET запрос:

В ответ нам присылаются данные за последний месяц:

Воспользуемся этим веб-сервисом для получения статистики. Создаём два класса — первый (назовём его Data.php) для формирования самого сообщения с статистикой за текущий день, а второй (назовём его Discord.php) — для отправки этого сообщения в канал «Коронавирус» нашего Discord сервера.
Листинг классов:
<?php
namespace Covid;
class Data
{
public static function GetTodayStats($regionCode, $regionName)
{
$R = false;
if (!$regionCode || !$regionName){
throw new \Exception('Не указан регион');
}
$jsonData = file_get_contents("https://xn--80aesfpebagmfblc0a.xn--p1ai/covid_data.json?do=region_stats&code={$regionCode}");
if ($jsonData){
$arData = json_decode($jsonData, true);
if ($arData[0]['date'] == date('d.m.Y')){
$R = self::FormatMessage($arData[0], $arData[1], $regionName);
}
}
return $R;
}
protected static function FormatMessage($todayData = [], $yesterdayData = [], $regionName)
{
$R = false;
if (!$todayData || !$yesterdayData || !$regionName){
throw new \Exception('Не указаны данные для формирования сообщения');
}
$R = "{$regionName}: статистика от **{$todayData['date']}**".PHP_EOL;
$R .= "Новых случаев: **".((int)$todayData['sick'] - (int)$yesterdayData['sick']).'**'.PHP_EOL;
$R .= "Выявлено всего: **{$todayData['sick']}".'**'.PHP_EOL;
$R .= "Выздоровело: **{$todayData['healed']}".'**'.PHP_EOL;
$R .= "Умерло: **{$todayData['died']}".'**'.PHP_EOL;
return $R;
}
}
<?php
namespace Covid;
class Discord
{
public static function Send($params)
{
if (!$params['regionCode'] || !$params['regionName'] || !$params['hookUrl']){
throw new \Exception('Не указан один из параметов вызова функции');
}
//Lock file
$lockFile = __DIR__.'/'.md5($params['hookUrl'].$params['regionCode'] );
$lastRunDate = file_get_contents($lockFile);
if ($lastRunDate == date('d.m.Y')){
return false;
}
$todayStats = Data::GetTodayStats($params['regionCode'], $params['regionName']);
if (!$todayStats){
return false;
}
$postData = [
'content' => $todayStats,
];
$curl = curl_init();
$postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
curl_setopt_array($curl, [
CURLOPT_URL => $params['hookUrl'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
],
]);
$response = curl_exec($curl);
curl_close($curl);
file_put_contents($lockFile, date('d.m.Y'));
return $response;
}
}
Теперь создаём третий файл (run-spe.php), на который будем обращаться по CRON-у каждую минуту для того, чтобы инициировать отправку статистики заражённых:
<?php
namespace Covid;
header('Content-type: text/html; charset=utf-8');
ini_set('display_errors', 1);
include __DIR__ . '/Data.php';
include __DIR__ . '/Discord.php';
$params = [
'hookUrl' => "{сюда пишем url вебхука канала, который мы создали}",
'regionCode' => 'RU-SPE',
'regionName' => 'Санкт-Петербург',
];
Discord::Send($params);
Собственно всё. Механика работы получается такой:
- каждую минуту сron обращается к
run-spe.php - в нём определяются параметры отправки сообщения (по какому вебхуку и с какого региона брать статистику)
- в классе
Discordполучаем статистику и если эта статистика ещё не была отправлена в канал дискорд сервера — отправляем - здесь фиксатором факта отправки сообщения является дата, которая записывается в файл с названием, хранящимся в переменной
$lockFile(смотри классDiscord)
В итоге мы получаем что-то вроде такой статистики, которая отправляется ежедневно:
