Пару месяцев назад мне надоело ежедневно тыкать сайт стопкоронавирус.рф с целью узнать статистику числа зараженных ковидом в моём городе. Так как по долгу службы я часто сижу в рабочем 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
)
В итоге мы получаем что-то вроде такой статистики, которая отправляется ежедневно:
