getUserInfoData($userCode); // $user = make(UserRepository::class)->getUserInfoFromCache($user_id); $columns = ['id','title', 'cover', 'like', 'uid', 'coins', 'pay_type', 'comment', 'mu', 'watch', 'resolution']; $ret = VideoModel::query() ->with(['type:type.id as type_id,type.title','user']) ->where('status', 1) ->find($id, $columns); if (!$ret) { throw new ApiException('没有此视频'); } //鉴权 $arrFlag = $this->videoAuth($user, $ret); /*$arrScreenshots = []; if (!empty($ret->screenshots)) { $arrTmp = explode(',', $ret->screenshots); foreach ($arrTmp as $v) { $arrScreenshots[] = M3u8CacheRepository::getImageUrl($v); } } $arrTags = []; if (!empty($ret->tags)) { $arrTmp = explode(',', $ret->tags); foreach ($arrTmp as $v) { $arrTags[] = $v; } } $ret->screenshots = $arrScreenshots; $ret->tags = $arrTags; $ret->cover = M3u8CacheRepository::getImageUrl($ret->cover); $ret->mu = M3u8CacheRepository::getVideoUrl($ret->mu);*/ $result = $ret->toArray(); $result['cover'] = M3u8CacheRepository::getImageUrl($result['cover']); if (!empty($result['user'])) { $result['user']['avatar'] = M3u8CacheRepository::getImageUrl($result['user']['avatar']); $result['user']['is_focus'] = $relationRepo->userIsFocusOtherUser($user['code'], $result['user']['code'], false); } $result['is_my_like'] = $relationRepo->userIsLikeVideo($user['code'], $result['id'], false); if (!empty($result['category'])) { foreach ($result['category'] as $ck => $t) { unset($result['category'][$ck]['pivot']); } } $result['auth_err'] = $arrFlag['err']; $result['video_surplus'] = $arrFlag['video_surplus']; $result['is_viewed'] = $arrFlag['is_viewed']; if ($result['auth_err']['key'] != 200) { // 非正常的,仅返回6秒预览m3u8地址. $m3u8Params1 = [ 'url' => $result['mu'], 'is_preview' => true, ]; $result['mu'] = M3u8CacheRepository::getVideoInnerUrl($m3u8Params1, $userCode, $id, 'video'); } else { $result['mu'] = M3u8CacheRepository::getVideoInnerUrl($result['mu'], $userCode, $id, 'video'); } $adItems = make(VideoService::class)->getAdList(AdConstrant::VIDEO_GUIDE); if (!empty($adItems)) { $ads = []; foreach ($adItems as $v) { $tmpLink = $v['link']; if (!empty($tmpLink)) { $tmpLink = M3u8CacheRepository::getLinkUrl($tmpLink, ['user_code' => $user->code]); } $ads[] = [ 'title' => $v['title'], 'cover' => M3u8CacheRepository::getImageUrl($v['cover']), 'link' => $tmpLink, 'scheme' => $v['scheme'], ]; } $result['ad'] = $ads; } $jobParams = [ [ 'date' => Carbon::now()->toDateString(), 'user_id' => $user['id'], 'user_code' => $user['code'], 'video_id' => $id, 'ad' => $ads ] ]; // 异步处理. dispatch_job(new VideoWatchedByBulkJob($jobParams)); return $result; } /** * 视频鉴权 * @return array */ public function videoAuth($user, $video) { $checkResult = [ 'result' => false, 'video_surplus' => 0, 'is_viewed' => false, 'err' => [ 'key' => 200, 'info' => '', ], ]; //先看今天看过这部视频没有 $data['date'] = Carbon::now()->toDateString(); $data['user_id'] = $user['id']; $data['video_id'] = $video->id; if ($user['code'] === $video->uid && !empty($video->uid)) { // 原创者自己的视频,不限制. $count = 1; } else { $key = $data['date'] .'_'. $data['user_id'] .'_'. $data['video_id']; $_id = substr(md5($key), 8, 16); $data['_id'] = $_id; $count = make(VideoHistoryModel::class)->db()->countDocuments( ['_id' => $_id] ); } // 今天一个人观看的次数统计. $realVideoViewedNum = make(VideoHistoryModel::class)->db()->countDocuments( ['uid' => $user['id'],'date' => $data['date']] ); $todayTaskVideoNum = make(TaskAwarkLogRepository::class)->coutTodayOnce($user['code'], TaskAwarkLogModel::REWARD_TYPE_MOVIE_CONUT); // 今日剩余观影次数 $videoSurplus = intval($user['max_view']) - $realVideoViewedNum + $todayTaskVideoNum; $oldSurplus = $videoSurplus; if ($user['is_vip'] == 'y') { $videoSurplus = 999999; } $isNegativeSurplus = false; // 是否是负数. if ($count) { // 观看过,依然允许他继续看. $checkResult['result'] = true; $checkResult['video_surplus'] = $videoSurplus; $checkResult['is_viewed'] = true; } else { $checkResult['result'] = true; //金币鉴权 if ($video->coins > 0) { $buyNum = UserBuyVideoModel::query()->where( [ 'user_id' => $user['id'], 'video_id' => $video->id, ] )->count(); if (!$buyNum) { // 没购买过,无法观看. $checkResult['result'] = false; $checkResult['err'] = [ 'key' => VideoConstant::VIDEO_COINS_NO, 'info' => VideoConstant::$messages[VideoConstant::VIDEO_COINS_NO], ]; } else { // 不管是不是会员,超过每日观影次数没有,都记录. $this->addHistory($data); } } else { // 不需要金币,则检查剩余次数. if ($user['is_vip'] != 'y') { // 非VIP情况 if ($videoSurplus > 0) { // 不管是不是会员,超过每日观影次数没有,都记录. $this->addHistory($data); $videoSurplus--; } else { $checkResult['result'] = false; $checkResult['err'] = [ 'key' => VideoConstant::VIDEO_LIMIT_NO, 'info' => VideoConstant::$messages[VideoConstant::VIDEO_LIMIT_NO], ]; } } else { $this->addHistory($data); } } } if ($videoSurplus < 0) { // 容错. $videoSurplus = 0; $isNegativeSurplus = true; } $checkResult['video_surplus'] = $videoSurplus; $userRepo = make(UserRepository::class); $userRepo->delUserCache($user['code']); // 清理这个用户的缓存. return $checkResult; } public function isLike($user_code, $video_id) { $key = $user_code .'_'. $video_id; $_id = substr(md5($key), 8, 16); $data = [ '_id' => $_id ]; $count = make(VideoLikeModel::class)->db()->countDocuments($data); if ($count) { $result = 1; } else { $result = 0; } return $result; } /** * 添加观影历史、更新观影次数 * @return mixed */ public function addHistory(array $data) { $result = make(VideoHistoryModel::class)->db()->insertOne( [ '_id' => $data['_id'], 'date' => $data['date'], 'uid' => $data['user_id'], 'vid' => $data['video_id'], ] ); return $result->getInsertedId(); } /** * 返回播放地址(没有用). * @param string $m3u8 * @return mixed */ public function getPlayUrl($m3u8) { return M3u8CacheRepository::getVideoUrl($m3u8); } /** * 返回广告内容 . * @param string $position * @return array */ public function getAdList($position) { $cacheKey = 'ad:' . $position; $ad = make(CacheInterface::class)->remember($cacheKey, 60 * 60, function () use ($position) { $items = AdModel::query() ->where('status', 1) ->where('position', '=', $position) ->orderBy('sort', 'DESC') ->get(); if ($items->count()) { return $items->toArray(); } else { return []; } }); return $ad; // $now = Carbon::now()->toDateString(); // // return collect($ad)->where('position', '=', $position) // ->where('start_time', '<=', $now) // ->where('end_time', '>=', $now) // ->all(); } /** * 用户购买视频. * @param $userCode * @param $videoId * @return mixed */ public function buyVideo($userCode, $videoId) { $userObj = UserModel::query()->where(['code' => $userCode])->first(); // 买家 $buyNum = UserBuyVideoModel::query()->where(['user_id' => $userObj->id, 'video_id' => $videoId])->count(); if ($buyNum) { throw new ApiException('您已经购买过,无需重复购买'); } $videoObj = VideoModel::query()->where(['id' => $videoId])->first(); if (empty($videoObj)) { throw new ApiException('视频不存在'); } if ($videoObj->pay_type == 2) { if ($videoObj->coins < 1) { throw new ApiException('此视频不可使用金币购买'); } } else { throw new ApiException('此视频不可使用金币购买'); } if (intval($userObj->coins) < intval($videoObj->coins)) { throw new ApiException(sprintf('您金币不足%s,请先购买金币', $videoObj->coins), VideoConstant::VIDEO_COINS_NO); } // 视频创作者 $creatorRepo = make(CreatorRepository::class); $creatorObj = $creatorRepo->detail($videoObj->uid); $isDeduction = 0; if (!empty($creatorObj->user_uid)) { $isDeduction = intval($creatorRepo->isDeduction($creatorObj->user_uid, $creatorObj->level)); // 是否扣量,默认不扣 } Db::beginTransaction(); $setarr = [ 'user_id' => $userObj->id, 'video_id' => $videoObj->id, 'is_deduction' => $isDeduction, ]; $buyObj = UserBuyVideoModel::query()->create($setarr); if (!$buyObj) { Db::rollBack(); return ''; } $userObj->coins = $userObj->coins - $videoObj->coins; if (!$userObj->save()) { Db::rollBack(); return ''; } Db::commit(); $jobParams = [ 'video_id' => $videoObj->id, 'buyer_uid' => $userObj->code, 'seller_uid' => !empty($creatorObj->user_uid) ? $creatorObj->user_uid : '', 'is_deduction' => $isDeduction, ]; if (empty($isDeduction)) { // 异步奖励创作者. dispatch_job(new AwardCreatorBuyVideoJob($jobParams)); } // 帐变记录 $changeData = [ 'user_uid' => $userObj->code, 'currency_type' => ChangeLogConstant::CHANGE_COIN, 'amount' => $videoObj->coins, 'way' => ChangeLogConstant::WAY_2, 'type' => ChangeLogConstant::TYPE_10, ]; make(QueueService::class)->saveChangeLogJob($changeData); // 清除缓存 make(UserRepository::class)->delUserCache($userObj->code); unset($userObj, $creatorObj); // 释放内存. return $videoObj; } }