| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- <?php
- namespace Modules\Api\Controllers;
- use App\Constants\CommonConstant;
- use App\Constants\VideoConstant;
- use App\Model\UserModel;
- use App\Repositories\AdRepository;
- use App\Repositories\OriginalRepository;
- use App\Repositories\Service\CommonService;
- use App\Repositories\ShopsRepository;
- use App\Repositories\UserRepository;
- use App\Repositories\Utils\JwtRepository;
- use App\Repositories\Utils\M3u8CacheRepository;
- use App\Repositories\VideoRepository;
- use Carbon\Carbon;
- use Hyperf\HttpServer\Request;
- use Modules\Api\Services\AuthService;
- use Psr\SimpleCache\CacheInterface;
- class M3u8Controller extends BaseController
- {
- /**
- * 获取raw
- * @param Request $request
- * @param VideoRepository $videoRepository
- * @param AdRepository $adRepository
- * @return \Psr\Http\Message\ResponseInterface
- */
- public function raw(Request $request, VideoRepository $videoRepository, AdRepository $adRepository, OriginalRepository $goodsRepository, ShopsRepository $shopsRepository)
- {
- $zuhe = urldecode($request->input('tk', ''));
- $module = trim(strtolower($request->input('module', '')));
- $pk = substr($request->input('pk', ''), 0, 16);
- $inputSign = $request->input('sn', '');
- $timestamp = intval($request->input('tm', 0));
- $rateType = substr($request->input('rate_type', ''), 0, 32); // 指定的比特率.
- $authService = new AuthService();
- if (empty($zuhe)) {
- return self::responseM3u8Raw('参数错误1', true);
- }
- if (!in_array($module, ['video', 'ad', 'goods', 'shop'])) {
- // 判断模块合法性.
- return self::responseM3u8Raw('参数错误2', true);
- }
- $nowDateObj = Carbon::now();
- $startCheckDate = '2022-08-01 04:45:33';
- $startCheckObj = Carbon::parse($startCheckDate);
- if ($nowDateObj > $startCheckObj && in_array($module, ['video'])) {
- // 大于这个日期, 且视频模块, 才检查签名参数.
- if (!empty($timestamp) && strlen($timestamp) == 10) {
- $inputDateObj = Carbon::createFromTimestamp($timestamp);
- if (abs($inputDateObj->diffInHours($nowDateObj)) >= 3) {
- return self::responseM3u8Raw('参数错误6', true);
- }
- } else {
- return self::responseM3u8Raw('参数错误7', true);
- }
- }
- $zuhe2 = caesar_decode($zuhe, 'l,n', 3); // 偏移了3
- $previewFlag = substr($zuhe2, 0, 2);
- $queryDeviceType = substr($zuhe2, 2, 1);
- $queryDeviceNo = substr($zuhe2, 7, strlen($zuhe2) - 7);
- $sign = M3u8CacheRepository::generateSign($zuhe2, $timestamp);
- if ($sign !== $inputSign) {
- return self::responseM3u8Raw('参数错误8', true);
- }
- $cacheKey = $authService->getUserDeviceCacheKey($queryDeviceNo, $queryDeviceType);
- $cache = make(CacheInterface::class);
- $cacheToken = $cache->has($cacheKey) ? $cache->get($cacheKey) : '';
- if (empty($cacheToken)) {
- return self::responseM3u8Raw('参数错误4', true);
- }
- $jwtRepo = make(JwtRepository::class);
- $aud = 'app-users';
- $validateResult = $jwtRepo->validateToken($cacheToken, $aud);
- if (!$validateResult['is_valid']) {
- if ($validateResult['is_expired']) {
- return self::responseM3u8Raw('参数错误2', true);
- }
- return self::responseM3u8Raw('参数错误3', true);
- }
- // 破解版专门一个m3u8
- $tokenObj = $validateResult['token_obj'];
- $hUserCode = $tokenObj->claims()->get('user_id');
- // $hDeviceNo = $tokenObj->claims()->get('device_no');
- $hDeviceType = $tokenObj->claims()->get('device_type');
- // $hFingerHash = $tokenObj->claims()->get('finger_hash');
- $hIp = $tokenObj->claims()->get('ip');
- $hVersion = $tokenObj->claims()->get('version');
- if ($hDeviceType == 'A') {
- if (version_compare($hVersion, '1.1.1', '<') || version_compare($hVersion, '1.99.1', '>')) {
- $crackedM3u8Url = 'v2|/20220831/pPlRwPcF/1000kb/hls/index.m3u8';
- $m3u8Params1 = [
- 'url' => $crackedM3u8Url,
- 'is_preview' => false,
- ];
- $raw = M3u8CacheRepository::getMu38Raw($m3u8Params1, true);
- return self::responseM3u8Raw($raw);
- }
- }
- // M3u8验证IP.
- $clientIp = make(CommonService::class)->getIp();
- if ($hIp !== $clientIp) {
- // make(UserRepository::class)->userLogout($hUserCode);
- logger('api-M3u8Controller-ip', ['token_ip' => $hIp, 'user_ip' => $clientIp]);
- // return self::responseM3u8Raw('参数错误9', true);
- }
- $cache = make(CacheInterface::class);
- $rateTypeKey = !empty($rateType) ? $rateType : 'empty';
- $cacheKey = $module . ':raw:'. $pk . ':'. $rateTypeKey;
- $cacheSeconds = 7 * 24 * 60 * 60;
- $arrItem = $cache->get($cacheKey, []);
- $m3u8PlayUrl = '';
- $previewTime = VideoConstant::PREVIEW_TIME;
- $playerType = 1;
- if (empty($arrItem)) {
- switch ($module) {
- case 'video':
- $item = $videoRepository->findBy('id', $pk, ['id', 'mu']);
- if (!empty($item->mu)) {
- $m3u8PlayUrl = $item->mu;
- }
- break;
- case 'ad':
- $item = $adRepository->findBy('id', $pk, ['id', 'play']);
- if (!empty($item->play)) {
- $m3u8PlayUrl = $item->play;
- }
- break;
- case 'shop':
- $item = $shopsRepository->findBy('uid', $pk, ['video_address']);
- if (!empty($item->video_address)) {
- $m3u8PlayUrl = $item->video_address;
- }
- break;
- case 'goods':
- $item = $goodsRepository->findBy('uid', $pk, ['video_address']);
- if (!empty($item->video_address)) {
- $m3u8PlayUrl = $item->video_address;
- }
- break;
- }
- if (empty($item)) {
- return self::responseM3u8Raw('参数错误5', true);
- }
- $arrItem = $item->toArray();
- $arrItem['m3u8_play_url'] = $m3u8PlayUrl;
- $cache->set($cacheKey, $arrItem, $cacheSeconds);
- }
- $isPreview = true; // 默认预览
- if ($previewFlag == 'k4') { // 标识 k4=完整,t5=预览
- $isPreview = false;
- }
- $m3u8FieldUrl = $arrItem['m3u8_play_url'];
- $itemInfo = [
- 'url' => $m3u8FieldUrl,
- 'is_preview' => $isPreview,
- // 'preview_time' => $previewTime,
- ];
- $raw = M3u8CacheRepository::getMu38Raw($itemInfo, true);
- return self::responseM3u8Raw($raw);
- }
- /**
- * @return string[]
- */
- private function getHeaders()
- {
- return [
- 'Content-Type' => 'application/x-mpegURL',
- ];
- }
- /**
- * 返回raw
- * @param $raw
- * @param bool $isError
- * @return \Psr\Http\Message\ResponseInterface
- */
- private function responseM3u8Raw($raw, $isError = false)
- {
- if (config('app_debug') && $isError == true && config('app_env') != 'prod') {
- return json_fail($raw);
- } else {
- if ($isError == true) {
- return response('', 200, self::getHeaders());
- } else {
- return response($raw, 200, self::getHeaders());
- }
- }
- }
- }
|