فهرست منبع

Merge branch 'master' of http://47.76.126.2:3000/seven/bot-28

lip 5 روز پیش
والد
کامیت
800ebcda74
4فایلهای تغییر یافته به همراه377 افزوده شده و 49 حذف شده
  1. 26 17
      app/Http/Controllers/admin/Issue.php
  2. 329 31
      app/Services/IssueService.php
  3. 13 1
      config/services.php
  4. 9 0
      example.env

+ 26 - 17
app/Http/Controllers/admin/Issue.php

@@ -155,32 +155,41 @@ class Issue extends Controller
             return $this->error(HttpStatus::CUSTOM_ERROR, '参数错误');
             return $this->error(HttpStatus::CUSTOM_ERROR, '参数错误');
         }
         }
         if (empty($winning_numbers)) {
         if (empty($winning_numbers)) {
-            $url = "https://ydpc28.co/api/pc28/list";
-            $result = file_get_contents($url);
-            $result = json_decode($result, true);
-            if ($result['errorCode'] != 0) {
-                return $this->error(HttpStatus::CUSTOM_ERROR, '参数错误');
-            }
             $issue = IssueService::findOne(['id' => $id]);
             $issue = IssueService::findOne(['id' => $id]);
-            foreach ($result['data']['list'] as $item) {
-                if ($item['lotNumber'] == $issue->issue_no) {
-                    $array = array_map('intval', str_split($item['openCode']));
-                    $winning_numbers = implode(',', $array);
-                    break;
-                }
+            if (!$issue) {
+                return $this->error(HttpStatus::CUSTOM_ERROR, '期号不存在');
             }
             }
-            if (empty($winning_numbers)) {
-                return $this->error(HttpStatus::CUSTOM_ERROR, '未查询到开奖信息,请手动开奖');
+
+            $playNowInfo = IssueService::getPlayNowWinningInfo($issue->issue_no);
+            if ($playNowInfo['code'] == IssueService::NOT) {
+                return $this->error(HttpStatus::CUSTOM_ERROR, $playNowInfo['msg']);
             }
             }
+
+            $winning_numbers = $playNowInfo['winning_numbers'];
         }
         }
-        if (explode(',', $winning_numbers) < 3) {
+        $winningNumberList = array_map('trim', explode(',', $winning_numbers));
+        if (count($winningNumberList) !== 3) {
             return $this->error(HttpStatus::CUSTOM_ERROR, '开奖号码格式错误');
             return $this->error(HttpStatus::CUSTOM_ERROR, '开奖号码格式错误');
         }
         }
-        $winArr = array_map('intval', explode(',', $winning_numbers));
+
+        $winArr = [];
+        foreach ($winningNumberList as $number) {
+            $value = filter_var($number, FILTER_VALIDATE_INT, [
+                'options' => [
+                    'min_range' => 0,
+                    'max_range' => 9,
+                ],
+            ]);
+            if ($value === false) {
+                return $this->error(HttpStatus::CUSTOM_ERROR, '开奖号码格式错误');
+            }
+            $winArr[] = (int)$value;
+        }
+        $winning_numbers = implode(',', $winArr);
         $combo = IssueService::getCombo($winArr);
         $combo = IssueService::getCombo($winArr);
         $ret = IssueService::lotteryDraw($id, $winning_numbers, $combo, "");
         $ret = IssueService::lotteryDraw($id, $winning_numbers, $combo, "");
         if ($ret['code'] == BaseService::NOT) {
         if ($ret['code'] == BaseService::NOT) {
-            return $this->error($ret['code'], isset($ret['error']) ?? $ret['msg']);
+            return $this->error($ret['code'], $ret['error'] ?? $ret['msg']);
         }
         }
         return $this->success([], $ret['msg']);
         return $this->success([], $ret['msg']);
     }
     }

+ 329 - 31
app/Services/IssueService.php

@@ -12,6 +12,7 @@ use App\Models\Config;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Log;
 
 
 use App\Services\GameplayRuleService;
 use App\Services\GameplayRuleService;
@@ -30,6 +31,10 @@ class IssueService extends BaseService
 {
 {
 
 
     const COUNTDOWN_TO_CLOSING_THE_MARKET = 60;//提前xx秒封盘
     const COUNTDOWN_TO_CLOSING_THE_MARKET = 60;//提前xx秒封盘
+    const PLAYNOW_KENO_URL = 'https://www.playnow.com/services2/keno/nextdraw';
+    const PLAYNOW_SOURCE_TIMEZONE = 'America/Vancouver';
+    const BEIJING_TIMEZONE = 'Asia/Shanghai';
+    const PLAYNOW_DRAW_INTERVAL_SECONDS = 210;
 
 
 
 
     public static function init($telegram, $data, $chatId, $firstName, $messageId): void
     public static function init($telegram, $data, $chatId, $firstName, $messageId): void
@@ -860,51 +865,335 @@ class IssueService extends BaseService
 
 
     }
     }
 
 
+    private static function getPlayNowConfig($key, $default)
+    {
+        $value = config('services.playnow.' . $key, $default);
+        return $value === null || $value === '' ? $default : $value;
+    }
+
+    private static function getPlayNowProxyUrl(): string
+    {
+        $scheme = self::getPlayNowConfig('proxy.scheme', 'http');
+        $host = self::getPlayNowConfig('proxy.host', '155.138.141.119');
+        $port = self::getPlayNowConfig('proxy.port', '3128');
+        $username = (string)self::getPlayNowConfig('proxy.username', 'proxyuser');
+        $password = (string)self::getPlayNowConfig('proxy.password', '');
+
+        if ($username === '' && $password === '') {
+            return "{$scheme}://{$host}:{$port}";
+        }
+
+        if ($password === '') {
+            return "{$scheme}://" . rawurlencode($username) . "@{$host}:{$port}";
+        }
+
+        return "{$scheme}://" . rawurlencode($username) . ':' . rawurlencode($password) . "@{$host}:{$port}";
+    }
+
+    private static function getPlayNowProxyLogContext(): array
+    {
+        $host = self::getPlayNowConfig('proxy.host', '155.138.141.119');
+        $password = self::getPlayNowConfig('proxy.password', '');
+
+        return [
+            'proxy' => $host === '' ? 'missing' : 'configured',
+            'proxy_auth' => $password === '' ? 'missing' : 'configured',
+        ];
+    }
+
+    private static function fetchPlayNowKenoResult()
+    {
+        $url = self::getPlayNowConfig('keno_url', self::PLAYNOW_KENO_URL);
+        $response = Http::timeout(25)
+            ->connectTimeout(10)
+            ->withHeaders([
+                'Accept' => 'application/json, text/plain, */*',
+                'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
+            ])
+            ->withOptions([
+                'proxy' => self::getPlayNowProxyUrl(),
+                'curl' => [
+                    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
+                ],
+            ])
+            ->get($url);
+
+        Log::channel('issue')->info('PlayNow接口响应', [
+            'status' => $response->status(),
+            'url' => $url,
+        ] + self::getPlayNowProxyLogContext());
+
+        if (!$response->successful()) {
+            Log::channel('issue')->info('PlayNow接口请求失败', [
+                'status' => $response->status(),
+                'body' => substr($response->body(), 0, 500),
+            ]);
+            return null;
+        }
+
+        return $response->json();
+    }
+
+    private static function convertPlayNowDrawDateToBeijing($drawDate)
+    {
+        if (empty($drawDate)) {
+            return null;
+        }
+
+        $sourceTimezone = new \DateTimeZone(self::getPlayNowConfig('timezone', self::PLAYNOW_SOURCE_TIMEZONE));
+        $beijingTimezone = new \DateTimeZone(self::BEIJING_TIMEZONE);
+
+        return (new \DateTimeImmutable($drawDate, $sourceTimezone))->setTimezone($beijingTimezone);
+    }
+
+    private static function getPlayNowDrawIntervalSeconds(array $result): int
+    {
+        $timeSinceDraw = isset($result['timeSinceDraw']) ? (int)$result['timeSinceDraw'] : 0;
+        $nextDrawSeconds = isset($result['nextKenoDrawTime']) ? (int)$result['nextKenoDrawTime'] : 0;
+
+        if ($timeSinceDraw > 0 && $nextDrawSeconds > 0) {
+            return (int)round($timeSinceDraw / 1000) + $nextDrawSeconds;
+        }
+
+        return $nextDrawSeconds > 0 ? $nextDrawSeconds : self::PLAYNOW_DRAW_INTERVAL_SECONDS;
+    }
+
+    private static function calculatePlayNowPc28(array $numbers): array
+    {
+        $sortedNumbers = array_map('intval', $numbers);
+        sort($sortedNumbers, SORT_NUMERIC);
+
+        $sumByIndexes = function (array $indexes) use ($sortedNumbers) {
+            $total = 0;
+            foreach ($indexes as $index) {
+                $total += $sortedNumbers[$index] ?? 0;
+            }
+            return $total % 10;
+        };
+
+        $firstNumber = $sumByIndexes([1, 4, 7, 10, 13, 16]);
+        $secondNumber = $sumByIndexes([2, 5, 8, 11, 14, 17]);
+        $thirdNumber = $sumByIndexes([3, 6, 9, 12, 15, 18]);
+
+        return [
+            'numbers' => [$firstNumber, $secondNumber, $thirdNumber],
+            'total' => $firstNumber + $secondNumber + $thirdNumber,
+            'sorted_numbers' => $sortedNumbers,
+        ];
+    }
+
+    private static function normalizePlayNowNumbers(array $numbers)
+    {
+        if (count($numbers) !== 20) {
+            return null;
+        }
+
+        $normalized = [];
+        foreach ($numbers as $number) {
+            $value = filter_var($number, FILTER_VALIDATE_INT, [
+                'options' => [
+                    'min_range' => 1,
+                    'max_range' => 80,
+                ],
+            ]);
+            if ($value === false) {
+                return null;
+            }
+            $normalized[] = (int)$value;
+        }
+
+        if (count(array_unique($normalized)) !== 20) {
+            return null;
+        }
+
+        return $normalized;
+    }
+
+    private static function isSamePlayNowIssueNo($issueNo, int $drawNo): bool
+    {
+        $issueNo = trim((string)$issueNo);
+        return ctype_digit($issueNo) && (int)$issueNo === $drawNo;
+    }
+
+    private static function normalizePlayNowDrawNo($drawNo)
+    {
+        $value = filter_var($drawNo, FILTER_VALIDATE_INT, [
+            'options' => [
+                'min_range' => 1,
+            ],
+        ]);
+
+        return $value === false ? null : (int)$value;
+    }
+
+    private static function parsePlayNowDrawInfo(array $result)
+    {
+        if (!isset($result['draw']) || empty($result['num']) || !is_array($result['num'])) {
+            return null;
+        }
+
+        $drawNo = self::normalizePlayNowDrawNo($result['draw']);
+        if (!$drawNo) {
+            return null;
+        }
+
+        $sourceNumbers = self::normalizePlayNowNumbers($result['num']);
+        if (!$sourceNumbers) {
+            return null;
+        }
+
+        try {
+            $drawDateBeijing = self::convertPlayNowDrawDateToBeijing($result['drawDate'] ?? null);
+        } catch (\Throwable $exception) {
+            Log::channel('issue')->info('PlayNow开奖时间解析失败', [
+                'draw_date_raw' => $result['drawDate'] ?? '',
+                'error' => $exception->getMessage(),
+            ]);
+            return null;
+        }
+
+        $nowBeijing = new \DateTimeImmutable('now', new \DateTimeZone(self::BEIJING_TIMEZONE));
+        $drawIntervalSeconds = self::getPlayNowDrawIntervalSeconds($result);
+        $startDateTime = $drawDateBeijing ?: $nowBeijing;
+        $endDateTime = $startDateTime->modify('+' . $drawIntervalSeconds . ' seconds');
+        $pc28 = self::calculatePlayNowPc28($sourceNumbers);
+
+        return [
+            'draw_no' => $drawNo,
+            'draw_date_raw' => $result['drawDate'] ?? '',
+            'draw_date_beijing' => $drawDateBeijing ? $drawDateBeijing->format('Y-m-d H:i:s') : '',
+            'next_draw_seconds' => $result['nextKenoDrawTime'] ?? '',
+            'draw_interval_seconds' => $drawIntervalSeconds,
+            'source_numbers' => $sourceNumbers,
+            'sorted_numbers' => $pc28['sorted_numbers'],
+            'pc28' => $pc28,
+            'winning_numbers' => implode(',', $pc28['numbers']),
+            'combo' => self::getCombo($pc28['numbers']),
+            'start_time' => $startDateTime->format('Y-m-d H:i:s'),
+            'end_time' => $endDateTime->format('Y-m-d H:i:s'),
+        ];
+    }
+
+    public static function getPlayNowWinningInfo($issueNo): array
+    {
+        Log::channel('issue')->info('后台手动开奖获取PlayNow数据', [
+            'issue_no' => $issueNo,
+        ] + self::getPlayNowProxyLogContext());
+
+        try {
+            $result = self::fetchPlayNowKenoResult();
+        } catch (\Throwable $exception) {
+            Log::channel('issue')->info('后台手动开奖获取PlayNow数据异常', [
+                'issue_no' => $issueNo,
+                'error' => $exception->getMessage(),
+                'file' => $exception->getFile(),
+                'line' => $exception->getLine(),
+            ]);
+            return ['code' => self::NOT, 'msg' => '获取开奖信息失败'];
+        }
+
+        $drawInfo = self::parsePlayNowDrawInfo($result ?: []);
+        if (!$drawInfo) {
+            Log::channel('issue')->info('后台手动开奖PlayNow返回数据格式异常', [
+                'issue_no' => $issueNo,
+                'result' => $result,
+            ]);
+            return ['code' => self::NOT, 'msg' => '获取开奖信息失败'];
+        }
+
+        Log::channel('issue')->info('后台手动开奖PlayNow计算结果', [
+            'issue_no' => $issueNo,
+            'draw' => $drawInfo['draw_no'],
+            'draw_date_raw' => $drawInfo['draw_date_raw'],
+            'draw_date_beijing' => $drawInfo['draw_date_beijing'],
+            'source_numbers' => implode(',', $drawInfo['source_numbers']),
+            'sorted_numbers' => implode(',', $drawInfo['sorted_numbers']),
+            'pc28_numbers' => $drawInfo['winning_numbers'],
+            'pc28_total' => $drawInfo['pc28']['total'],
+            'combo' => $drawInfo['combo'],
+        ]);
+
+        if (!self::isSamePlayNowIssueNo($issueNo, $drawInfo['draw_no'])) {
+            Log::channel('issue')->info('后台手动开奖期号不匹配', [
+                'issue_no' => $issueNo,
+                'playnow_draw' => $drawInfo['draw_no'],
+            ]);
+            return ['code' => self::NOT, 'msg' => '未查询到开奖信息,请手动开奖'];
+        }
+
+        return ['code' => self::YES, 'msg' => '获取成功'] + $drawInfo;
+    }
+
 // 获取最新的开奖数据
 // 获取最新的开奖数据
     public static function getLatestIssue()
     public static function getLatestIssue()
     {
     {
-        Log::channel('issue')->info('开始获取最新期号');
-        $url = "https://ydpc28.co/api/pc28/list";
-        $result = file_get_contents($url);
-        $result = json_decode($result, true);
-        if ($result['errorCode'] != 0) {
-            Log::channel('issue')->info('获取最新期号失败');
+        Log::channel('issue')->info('开始获取最新期号', [
+            'source' => 'playnow',
+        ] + self::getPlayNowProxyLogContext());
+
+        try {
+            $result = self::fetchPlayNowKenoResult();
+        } catch (\Throwable $exception) {
+            Log::channel('issue')->info('获取PlayNow最新期号异常', [
+                'error' => $exception->getMessage(),
+                'file' => $exception->getFile(),
+                'line' => $exception->getLine(),
+            ]);
             return ['code' => self::NOT, 'msg' => '获取最新期号失败'];
             return ['code' => self::NOT, 'msg' => '获取最新期号失败'];
+        }
 
 
+        $drawInfo = self::parsePlayNowDrawInfo($result ?: []);
+        if (!$drawInfo) {
+            Log::channel('issue')->info('PlayNow返回数据格式异常', [
+                'result' => $result,
+            ]);
+            return ['code' => self::NOT, 'msg' => '获取最新期号失败'];
         }
         }
-        $nextDrawInfo = $result['data']['nextDrawInfo'];
-        $startTime = $nextDrawInfo['currentBJTime'];
-        // if($nextDrawInfo['nextDrawTime'] >= date('H:i:s')) {
-        //     $endTime = date('Y-m-d').' '.$nextDrawInfo['nextDrawTime']; // 下一期的截止时间
-        // }else{
-        //     $endTime = date('Y-m-d',strtotime('+1 day')).' '.$nextDrawInfo['nextDrawTime']; // 下一期的截止时间
-        // }
 
 
-        $endTime = date('Y-m-d H:i:s', strtotime($startTime) + 210);
+        $drawNo = $drawInfo['draw_no'];
+        $startTime = $drawInfo['start_time'];
+        $endTime = $drawInfo['end_time'];
+        $pc28 = $drawInfo['pc28'];
+
+        Log::channel('issue')->info('PlayNow最新开奖数据', [
+            'draw' => $drawNo,
+            'draw_date_raw' => $drawInfo['draw_date_raw'],
+            'draw_date_beijing' => $drawInfo['draw_date_beijing'],
+            'next_draw_seconds' => $drawInfo['next_draw_seconds'],
+            'draw_interval_seconds' => $drawInfo['draw_interval_seconds'],
+            'source_numbers' => implode(',', $drawInfo['source_numbers']),
+            'sorted_numbers' => implode(',', $drawInfo['sorted_numbers']),
+            'pc28_numbers' => $drawInfo['winning_numbers'],
+            'pc28_total' => $pc28['total'],
+            'next_issue_start_time' => $startTime,
+            'next_issue_end_time' => $endTime,
+        ]);
 
 
         $new = true;
         $new = true;
 
 
-        $list = $result['data']['list'];
-        $listKey = [];
-        foreach ($list as $k => $v) {
-            $listKey[$v['lotNumber']] = $v;
-        }
-
         $oldList = self::findAll(['status' => self::model()::STATUS_CLOSE]);    // 获取所有封盘的期号
         $oldList = self::findAll(['status' => self::model()::STATUS_CLOSE]);    // 获取所有封盘的期号
         foreach ($oldList as $k => $v) {
         foreach ($oldList as $k => $v) {
-            if (isset($listKey[$v->issue_no])) {
-                $issue = $listKey[$v->issue_no];
-                $winning_numbers = implode(',', str_split((string)$issue['openCode']));
+            if (self::isSamePlayNowIssueNo($v->issue_no, $drawNo)) {
+                $winning_numbers = $drawInfo['winning_numbers'];
+                $winArr = $pc28['numbers'];
 
 
-                $winArr = array_map('intval', explode(',', $winning_numbers));
 
 
-
-                $combo = static::getCombo($winArr);
+                $combo = $drawInfo['combo'];
                 $key = 'lottery_numbers_' . $v->issue_no;
                 $key = 'lottery_numbers_' . $v->issue_no;
                 if (Cache::add($key, $winning_numbers, 100)) {
                 if (Cache::add($key, $winning_numbers, 100)) {
-                    Log::channel('issue')->info('开奖期号: ' . $v->issue_no . ' 开奖号码: ' . $winning_numbers);
+                    Log::channel('issue')->info('开奖期号: ' . $v->issue_no . ' 开奖号码: ' . $winning_numbers, [
+                        'source' => 'playnow',
+                        'draw' => $drawNo,
+                        'combo' => $combo,
+                        'pc28_total' => $pc28['total'],
+                    ]);
                     self::lotteryDraw($v->id, $winning_numbers, $combo, '');
                     self::lotteryDraw($v->id, $winning_numbers, $combo, '');
                     $new = false;
                     $new = false;
+                } else {
+                    Log::channel('issue')->info('开奖期号已处理,跳过重复开奖', [
+                        'issue_no' => $v->issue_no,
+                        'winning_numbers' => $winning_numbers,
+                    ]);
                 }
                 }
                 $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
                 $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
                 //更新游戏开关的切换
                 //更新游戏开关的切换
@@ -915,15 +1204,17 @@ class IssueService extends BaseService
         // sleep(5); // 等待开奖完成
         // sleep(5); // 等待开奖完成
 
 
         if ($new) {
         if ($new) {
-            $latestIssue = $list[0];    // 最后开奖
-
-            $new_issue_no = $latestIssue['lotNumber'] + 1;  // 新期号
+            $new_issue_no = $drawNo + 1;  // 新期号
 
 
             $newInfo = self::findOne(['issue_no' => $new_issue_no]);   // 找新的期号
             $newInfo = self::findOne(['issue_no' => $new_issue_no]);   // 找新的期号
 
 
             // 不存在
             // 不存在
             if (!$newInfo) {
             if (!$newInfo) {
-                Log::channel('issue')->info('新增期号: ' . $new_issue_no);
+                Log::channel('issue')->info('新增期号: ' . $new_issue_no, [
+                    'source' => 'playnow',
+                    'start_time' => $startTime,
+                    'end_time' => $endTime,
+                ]);
                 $res = self::submit([
                 $res = self::submit([
                     'issue_no' => $new_issue_no,
                     'issue_no' => $new_issue_no,
                     'status' => self::model()::STATUS_DRAFT,
                     'status' => self::model()::STATUS_DRAFT,
@@ -940,6 +1231,13 @@ class IssueService extends BaseService
 
 
                 }
                 }
                 Cache::set('new_issue_no', $new_issue_no, 10); // 缓存
                 Cache::set('new_issue_no', $new_issue_no, 10); // 缓存
+            } else {
+                Log::channel('issue')->info('期号已存在,无需新增', [
+                    'issue_no' => $new_issue_no,
+                    'status' => $newInfo->status,
+                    'start_time' => $newInfo->start_time,
+                    'end_time' => $newInfo->end_time,
+                ]);
             }
             }
         }
         }
         
         

+ 13 - 1
config/services.php

@@ -54,6 +54,18 @@ return [
     'apple' => [
     'apple' => [
         'shared_secret' => env('APPLE_SHARED_SECRET', ''),
         'shared_secret' => env('APPLE_SHARED_SECRET', ''),
         'verify_receipt_uri' => env('APPLE_VERIFY_RECEIPT_URI', ''),
         'verify_receipt_uri' => env('APPLE_VERIFY_RECEIPT_URI', ''),
-    ]
+    ],
+
+    'playnow' => [
+        'keno_url' => env('PLAYNOW_KENO_URL', 'https://www.playnow.com/services2/keno/nextdraw'),
+        'timezone' => env('PLAYNOW_TIMEZONE', 'America/Vancouver'),
+        'proxy' => [
+            'scheme' => env('PLAYNOW_PROXY_SCHEME', 'http'),
+            'host' => env('PLAYNOW_PROXY_HOST', '155.138.141.119'),
+            'port' => env('PLAYNOW_PROXY_PORT', '3128'),
+            'username' => env('PLAYNOW_PROXY_USERNAME', 'proxyuser'),
+            'password' => env('PLAYNOW_PROXY_PASSWORD', ''),
+        ],
+    ],
 
 
 ];
 ];

+ 9 - 0
example.env

@@ -8,6 +8,15 @@ APP_URL=
 #足球接口域名
 #足球接口域名
 FOOTBALL_APP_URL=https://api.8xbet001.com
 FOOTBALL_APP_URL=https://api.8xbet001.com
 
 
+# PlayNow Keno开奖接口
+PLAYNOW_KENO_URL=https://www.playnow.com/services2/keno/nextdraw
+PLAYNOW_TIMEZONE=America/Vancouver
+PLAYNOW_PROXY_SCHEME=http
+PLAYNOW_PROXY_HOST=155.138.141.119
+PLAYNOW_PROXY_PORT=3128
+PLAYNOW_PROXY_USERNAME=proxyuser
+PLAYNOW_PROXY_PASSWORD=
+
 # 足球数据API平台的秘钥和地址
 # 足球数据API平台的秘钥和地址
 API_FOOTBALL_KEY=b60ecb5e998be566e592068b3f6d98b1
 API_FOOTBALL_KEY=b60ecb5e998be566e592068b3f6d98b1
 API_FOOTBALL_HOST=https://v3.football.api-sports.io
 API_FOOTBALL_HOST=https://v3.football.api-sports.io