Modules_Api_Controllers_PerfectController.proxy.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. <?php
  2. namespace Modules\Api\Controllers;
  3. use App\Constants\AdConstrant;
  4. use App\Constants\CategoryConstant;
  5. use App\Constants\CommonConstant;
  6. use App\Model\CommentModel;
  7. use App\Model\Mongo\MessageModel;
  8. use App\Model\Mongo\UserRelationModel;
  9. use App\Model\Mongo\VideoLikeModel;
  10. use App\Model\UserModel;
  11. use App\Model\VideoModel;
  12. use App\Repositories\CategoryRepository;
  13. use App\Repositories\CommentRepository;
  14. use App\Repositories\ConfigRepoistory;
  15. use App\Repositories\CreatorRepository;
  16. use App\Repositories\MessageRepository;
  17. use App\Repositories\RelationRepository;
  18. use App\Repositories\Utils\M3u8CacheRepository;
  19. use App\Repositories\VideoRepository;
  20. use Carbon\Carbon;
  21. use Hyperf\Validation\Contract\ValidatorFactoryInterface;
  22. use Modules\Api\Services\VideoService;
  23. class PerfectController extends BaseController
  24. {
  25. use \Hyperf\Di\Aop\ProxyTrait;
  26. use \Hyperf\Di\Aop\PropertyHandlerTrait;
  27. function __construct()
  28. {
  29. if (method_exists(parent::class, '__construct')) {
  30. parent::__construct(...func_get_args());
  31. }
  32. $this->__handlePropertyHandler(__CLASS__);
  33. }
  34. public function home()
  35. {
  36. $userCode = $this->getUserId();
  37. $videoService = make(VideoService::class);
  38. $adList1 = $videoService->getAdList(AdConstrant::PERFECT_HOME1);
  39. $ads1 = null;
  40. if (!empty($adList1)) {
  41. $ads1 = [];
  42. foreach ($adList1 as $v) {
  43. $linkUrl = $v['link'];
  44. if (!empty($linkUrl)) {
  45. $linkUrl = M3u8CacheRepository::getLinkUrl($linkUrl, ['user_code' => $userCode]);
  46. }
  47. $ads1[] = ['title' => $v['title'], 'cover' => !empty($v['cover']) ? M3u8CacheRepository::getImageUrl($v['cover']) : '', 'link' => $linkUrl, 'scheme' => $v['scheme']];
  48. }
  49. }
  50. $creatorRepo = make(CreatorRepository::class);
  51. $topCreators = $creatorRepo->getTopUsersByIncome();
  52. $result = ['top_creators' => $topCreators, 'ads1' => $ads1, 'top10' => [], 'cates' => []];
  53. $categoryRepo = make(CategoryRepository::class);
  54. $top10Position = CategoryConstant::POSITION_JINGPING_TOP;
  55. $topCates = $categoryRepo->findAllByPosition($top10Position);
  56. if (!empty($topCates['0']['alias_name'])) {
  57. $top10Alias = $topCates['0']['alias_name'];
  58. $top10Num = $topCates['0']['show_num'] ?? 10;
  59. $top10Videos = $categoryRepo->getVideos($top10Alias, $top10Num);
  60. if (!empty($top10Videos)) {
  61. foreach ($top10Videos as &$v) {
  62. $v['mu'] = '';
  63. // 列表干掉m3u8地址.
  64. // $v['mu'] = !empty($v['mu']) ? M3u8CacheRepository::getVideoInnerUrl($v['mu'], $userCode, $v['id'], 'video') : '';
  65. }
  66. }
  67. $result['top10'] = $top10Videos;
  68. }
  69. $channelPosition = CategoryConstant::POSTION_JINGPING_CHANNEL;
  70. $channelCates = $categoryRepo->findAllByPosition($channelPosition);
  71. if (!empty($channelCates)) {
  72. foreach ($channelCates as $item) {
  73. $channelAliasName = $item['alias_name'];
  74. $showNum = $item['show_num'] ?? 10;
  75. $channelName = $item['name'];
  76. $videoItems = $categoryRepo->getVideos($channelAliasName, $showNum);
  77. if (!empty($videoItems)) {
  78. foreach ($videoItems as &$v) {
  79. $v['mu'] = '';
  80. // 列表干掉m3u8地址.
  81. // $v['mu'] = !empty($v['mu']) ? M3u8CacheRepository::getVideoInnerUrl($v['mu'], $userCode, $v['id'], 'video') : '';
  82. }
  83. }
  84. $result['cates'][] = ['name' => $channelName, 'alias_name' => $channelAliasName, 'items' => $videoItems];
  85. }
  86. }
  87. return json_success($result);
  88. }
  89. public function homeCases()
  90. {
  91. $userCode = $this->getUserId();
  92. $videoService = make(VideoService::class);
  93. $adList1 = $videoService->getAdList(AdConstrant::PERFECT_HOME1);
  94. $ads1 = null;
  95. if (!empty($adList1)) {
  96. $ads1 = [];
  97. foreach ($adList1 as $v) {
  98. $linkUrl = $v['link'];
  99. if (!empty($linkUrl)) {
  100. $linkUrl = M3u8CacheRepository::getLinkUrl($linkUrl, ['user_code' => $userCode]);
  101. }
  102. $ads1[] = ['title' => $v['title'], 'cover' => !empty($v['cover']) ? M3u8CacheRepository::getImageUrl($v['cover']) : '', 'link' => $linkUrl, 'scheme' => $v['scheme']];
  103. }
  104. }
  105. $result = ['ads1' => $ads1, 'cates' => []];
  106. $categoryRepo = make(CategoryRepository::class);
  107. $channelPosition = CategoryConstant::POSTION_JINGXIAN;
  108. $channelCates = $categoryRepo->findAllByPosition($channelPosition);
  109. if (!empty($channelCates)) {
  110. foreach ($channelCates as $item) {
  111. $channelAliasName = $item['alias_name'];
  112. $channelName = $item['name'];
  113. $result['cates'][] = ['name' => $channelName, 'alias_name' => $channelAliasName];
  114. }
  115. }
  116. return json_success($result);
  117. }
  118. /**
  119. * 系统消息分页.
  120. * @return mixed
  121. */
  122. public function sysPages()
  123. {
  124. $userCode = $this->getUserId();
  125. $inputData = $this->getJsonData();
  126. $previousDate = isset($inputData['previous_date']) ? trim($inputData['previous_date']) : '';
  127. if (empty($previousDate)) {
  128. $previousDate = Carbon::now()->toDateTimeString();
  129. }
  130. $limitNum = 20;
  131. $result = ['previous_date' => $previousDate, 'data' => null];
  132. $items = make(MessageRepository::class)->previousSysPages($userCode, $previousDate, $limitNum, true);
  133. if (!empty($items)) {
  134. $result['data'] = $items;
  135. }
  136. return json_success($result);
  137. }
  138. /**
  139. * 标记消息为已读.
  140. * @return mixed|void
  141. */
  142. public function doRead()
  143. {
  144. $userCode = $this->getUserId();
  145. $inputData = $this->getJsonData();
  146. $msgId = isset($inputData['msg_id']) ? trim($inputData['msg_id']) : '';
  147. if (empty($msgId)) {
  148. return json_fail('参数有误1');
  149. }
  150. if (!preg_match('/^[a-z0-9]{16,32}$/i', $msgId)) {
  151. return json_fail('参数有误2');
  152. }
  153. $result = make(MessageRepository::class)->doRead($msgId, $userCode);
  154. if (!$result) {
  155. return json_fail('不能正确操作已读');
  156. }
  157. return json_success(['result' => 'success']);
  158. }
  159. /**
  160. * 删除自己的消息.
  161. * @return mixed
  162. */
  163. public function deleteMyself()
  164. {
  165. $userCode = $this->getUserId();
  166. $inputData = $this->getJsonData();
  167. $msgIds = isset($inputData['msg_ids']) ? trim($inputData['msg_ids']) : '';
  168. $receiveUid = $userCode;
  169. if (empty($msgIds)) {
  170. return json_fail('缺少参数1');
  171. }
  172. $arrMsgIds = [];
  173. if (is_string($msgIds)) {
  174. if (stripos($msgIds, ',') !== false) {
  175. $arrMsgIds = explode(',', $msgIds);
  176. } else {
  177. $arrMsgIds[] = $msgIds;
  178. }
  179. } else {
  180. $arrMsgIds = $msgIds;
  181. }
  182. $result = make(MessageRepository::class)->slientDelete($arrMsgIds, $userCode);
  183. if (!$result) {
  184. return json_fail('删除消息有误.');
  185. }
  186. return json_success(['result' => 'success']);
  187. }
  188. /**
  189. * 被关注分页列表
  190. */
  191. public function followedPages()
  192. {
  193. $userCode = $this->getUserId();
  194. $inputData = $this->getJsonData();
  195. $validatorFactory = make(ValidatorFactoryInterface::class);
  196. $rules = ['page' => 'nullable|int', 'page_size' => 'nullable|int'];
  197. $validator = $validatorFactory->make($inputData, $rules);
  198. if ($validator->fails()) {
  199. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  200. return json_fail($validator->errors()->first());
  201. }
  202. $page = $inputData['page'] ?? 1;
  203. $pageSize = $inputData['page_size'] ?? CommonConstant::PAGE_SIZE;
  204. if ($pageSize > 100) {
  205. $pageSize = CommonConstant::PAGE_SIZE;
  206. }
  207. $page = format_page($page);
  208. $pageSize = intval($pageSize);
  209. $relationRepo = make(UserRelationModel::class);
  210. $filters = ['to_user_id' => $userCode];
  211. $amount = $relationRepo->db()->countDocuments($filters);
  212. $skip = ($page - 1) * $pageSize;
  213. $options = ['skip' => $skip, 'limit' => $pageSize, 'sort' => ['date' => -1]];
  214. $temItems = $relationRepo->db()->find($filters, $options)->toArray();
  215. $data = [];
  216. $result = ['current_page' => $page, 'per_page' => $pageSize, 'total' => $amount, 'data' => []];
  217. if (!empty($temItems)) {
  218. foreach ($temItems as $item) {
  219. $fromUserCode = $item['from_user_id'];
  220. $fromUser = UserModel::query()->where('code', $fromUserCode)->first(['id', 'code', 'nick', 'avatar']);
  221. if ($fromUser) {
  222. $fromUser = $fromUser->toArray();
  223. $fromUser['avatar'] = M3u8CacheRepository::getImageUrl($fromUser['avatar']);
  224. $fromUser['date'] = Carbon::parse($item['date'])->toDateTimeString();
  225. unset($fromUser['id']);
  226. $data[] = $fromUser;
  227. }
  228. }
  229. }
  230. $result['data'] = $data;
  231. return json_success($result);
  232. }
  233. /**
  234. * 被点赞视频分页列表
  235. */
  236. public function likedPages()
  237. {
  238. $userCode = $this->getUserId();
  239. $inputData = $this->getJsonData();
  240. $validatorFactory = make(ValidatorFactoryInterface::class);
  241. $rules = ['page' => 'nullable|int', 'page_size' => 'nullable|int'];
  242. $validator = $validatorFactory->make($inputData, $rules);
  243. if ($validator->fails()) {
  244. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  245. return json_fail($validator->errors()->first());
  246. }
  247. $page = $inputData['page'] ?? 1;
  248. $pageSize = $inputData['page_size'] ?? CommonConstant::PAGE_SIZE;
  249. if ($pageSize > 100) {
  250. $pageSize = CommonConstant::PAGE_SIZE;
  251. }
  252. $page = format_page($page);
  253. $pageSize = intval($pageSize);
  254. $relationRepo = make(VideoLikeModel::class);
  255. $filters = ['uid' => $userCode];
  256. $amount = $relationRepo->db()->countDocuments($filters);
  257. $skip = ($page - 1) * $pageSize;
  258. $options = ['skip' => $skip, 'limit' => $pageSize, 'sort' => ['date' => -1]];
  259. $temItems = $relationRepo->db()->find($filters, $options)->toArray();
  260. $data = [];
  261. $result = ['current_page' => $page, 'per_page' => $pageSize, 'total' => $amount, 'data' => []];
  262. $cacheVideo = [];
  263. if (!empty($temItems)) {
  264. $videoColumns = ['id', 'uid', 'title', 'cover'];
  265. foreach ($temItems as $item) {
  266. $fromUserCode = $item['uid'];
  267. $videoId = $item['vid'];
  268. if (empty($cacheVideo[$videoId])) {
  269. $videoInfo = VideoModel::query()->where(['status' => 1])->find($videoId, $videoColumns);
  270. if (empty($videoInfo)) {
  271. break;
  272. }
  273. $videoInfo = $videoInfo->toArray();
  274. $cacheVideo[$videoId] = $videoInfo;
  275. } else {
  276. $videoInfo = $cacheVideo[$videoId];
  277. }
  278. $fromUser = UserModel::query()->where('code', $fromUserCode)->first(['id', 'code', 'nick', 'avatar']);
  279. if ($fromUser) {
  280. $fromUser = $fromUser->toArray();
  281. $fromUser['avatar'] = M3u8CacheRepository::getImageUrl($fromUser['avatar']);
  282. $fromUser['date'] = Carbon::parse($item['date'])->toDateTimeString();
  283. $fromUser['video'] = ['id' => $videoInfo['id'], 'title' => $videoInfo['title'], 'cover' => M3u8CacheRepository::getImageUrl($videoInfo['cover']), 'uid' => $videoInfo['uid']];
  284. unset($fromUser['id']);
  285. $data[] = $fromUser;
  286. }
  287. }
  288. }
  289. $result['data'] = $data;
  290. return json_success($result);
  291. }
  292. /**
  293. * 被评论分页列表
  294. */
  295. public function commentedPages()
  296. {
  297. $userCode = $this->getUserId();
  298. $inputData = $this->getJsonData();
  299. $validatorFactory = make(ValidatorFactoryInterface::class);
  300. $rules = ['page' => 'nullable|int', 'page_size' => 'nullable|int'];
  301. $validator = $validatorFactory->make($inputData, $rules);
  302. if ($validator->fails()) {
  303. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  304. return json_fail($validator->errors()->first());
  305. }
  306. $page = $inputData['page'] ?? 1;
  307. $pageSize = $inputData['page_size'] ?? CommonConstant::PAGE_SIZE;
  308. if ($pageSize > 100) {
  309. $pageSize = CommonConstant::PAGE_SIZE;
  310. }
  311. $page = format_page($page);
  312. $pageSize = intval($pageSize);
  313. if ($pageSize <= 0) {
  314. $pageSize = CommonConstant::PAGE_SIZE;
  315. }
  316. $columns = ['id', 'user_id', 'module', 'svalue', 'content', 'created_at'];
  317. $items = CommentModel::query()->where(['module_user_uid' => $userCode])->orderByDesc('created_at')->paginate($pageSize, $columns, 'page', $page);
  318. $result = $items->toArray();
  319. $cacheData = ['video' => []];
  320. if (!empty($result['data'])) {
  321. $videoColumns = ['id', 'uid', 'title', 'cover'];
  322. foreach ($result['data'] as $k => &$v) {
  323. $fromUserCode = $v['user_id'];
  324. $moduleInfo = [];
  325. if ($v['module'] == 'video') {
  326. $videoId = $v['svalue'];
  327. if (empty($cacheData['video'][$videoId])) {
  328. $videoInfo = VideoModel::query()->where(['status' => 1])->find($videoId, $videoColumns);
  329. if (!empty($videoInfo)) {
  330. $videoInfo = $videoInfo->toArray();
  331. $cacheData['video'][$videoId] = $videoInfo;
  332. }
  333. } else {
  334. $videoInfo = $cacheData['video'][$videoId];
  335. }
  336. $moduleInfo = [
  337. 'module' => $v['module'],
  338. 'id' => !empty($videoInfo['id']) ? (string) $videoInfo['id'] : '',
  339. // 强语言,统一转换字符串.
  340. 'title' => !empty($videoInfo['title']) ? $videoInfo['title'] : '视频已下架',
  341. 'cover' => !empty($videoInfo['cover']) ? M3u8CacheRepository::getImageUrl($videoInfo['cover']) : '',
  342. 'uid' => !empty($videoInfo['uid']) ? $videoInfo['uid'] : '',
  343. ];
  344. }
  345. $fromUser = UserModel::query()->where('code', $fromUserCode)->first(['id', 'code', 'nick', 'avatar']);
  346. if ($fromUser) {
  347. $fromUser = $fromUser->toArray();
  348. $fromUser['avatar'] = M3u8CacheRepository::getImageUrl($fromUser['avatar']);
  349. $fromUser['date'] = $v['created_at'];
  350. $fromUser['module_info'] = $moduleInfo;
  351. unset($fromUser['id']);
  352. } else {
  353. $fromUser = null;
  354. }
  355. $result['data'][$k] = $fromUser;
  356. }
  357. }
  358. return json_success($result);
  359. }
  360. /**
  361. * 私聊用户列表
  362. *
  363. * @param ValidatorFactoryInterface $validatorFactory
  364. * @return mixed
  365. */
  366. public function privateChatLists(ValidatorFactoryInterface $validatorFactory)
  367. {
  368. $inputData = $this->getJsonData();
  369. $rules = ['page' => 'required|integer', 'page_size' => 'required|integer'];
  370. $validator = $validatorFactory->make($inputData, $rules);
  371. if ($validator->fails()) {
  372. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  373. return json_fail($validator->errors()->first());
  374. }
  375. $pageSize = $inputData['page_size'] ?? CommonConstant::PAGE_SIZE;
  376. if ($pageSize > 500) {
  377. $pageSize = CommonConstant::PAGE_SIZE;
  378. }
  379. $page = format_page($inputData['page'] ?? 1);
  380. $result = make(MessageModel::class)->db()->aggregate([['$match' => ['receive_uid' => $this->getUserId(), 'from_type' => 'user']], ['$group' => ["_id" => ['from_uid' => '$from_uid'], 'struct_type' => ['$first' => '$struct_type'], 'from_uid' => ['$first' => '$from_uid'], 'from_nick' => ['$first' => '$from_nick'], 'from_avatar' => ['$first' => '$from_avatar'], 'content' => ['$first' => '$content'], 'created_at' => ['$first' => '$created_at']]], ['$sort' => ["created_at" => -1]], ['$limit' => $pageSize * $page], ['$skip' => ($page - 1) * $pageSize]]);
  381. $res = $result->toArray();
  382. if (!empty($res)) {
  383. foreach ($res as &$val) {
  384. $val['created_at'] = mongoIsoDateToCarbonTime($val['created_at'])->toDateTimeString();
  385. $val['from_avatar'] = M3u8CacheRepository::getImageUrl($val['from_avatar']);
  386. unset($val['_id']);
  387. }
  388. }
  389. return json_success($res);
  390. }
  391. /**
  392. * 分类别名下的视频分页(有缓存)
  393. * @return mixed
  394. * @throws \Psr\SimpleCache\InvalidArgumentException
  395. */
  396. public function videoPagesByCategoryName()
  397. {
  398. $userCode = $this->getUserId();
  399. $validatorFactory = make(ValidatorFactoryInterface::class);
  400. $inputData = $this->getJsonData();
  401. $rules = ['page' => 'nullable|int', 'page_size' => 'nullable|int', 'cate_alias_name' => 'required'];
  402. $validator = $validatorFactory->make($inputData, $rules);
  403. if ($validator->fails()) {
  404. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  405. return json_fail($validator->errors()->first());
  406. }
  407. $page = $inputData['page'] ?? 1;
  408. $pageSize = $inputData['page_size'] ?? CommonConstant::PAGE_SIZE;
  409. if ($pageSize > 100) {
  410. $pageSize = CommonConstant::PAGE_SIZE;
  411. }
  412. $page = format_page($page);
  413. $pageSize = intval($pageSize);
  414. $videoRepo = make(VideoRepository::class);
  415. $cateAliasName = data_get($inputData, 'cate_alias_name', '');
  416. $arrData = [];
  417. $lists = $videoRepo->pagesByCategoryAlias($cateAliasName, $page, $pageSize);
  418. if (!empty($lists['data'])) {
  419. $relationRepo = make(RelationRepository::class);
  420. $videoService = make(VideoService::class);
  421. $arrAds = $videoService->getAdList(AdConstrant::VIDEO_HOME);
  422. $adStep = 1;
  423. $configRepo = make(ConfigRepoistory::class);
  424. $stepDelimiter = intval($configRepo->get('ad_delimiter_num', 'sys', 10));
  425. // 间隔视频几个出现视频.
  426. foreach ($lists['data'] as $k => $v) {
  427. $v['mu'] = '';
  428. // 列表干掉m3u8地址.
  429. // $v['mu'] = M3u8CacheRepository::getVideoInnerUrl($v['mu'], $userCode, $v['id'], 'video');
  430. $v['cover'] = M3u8CacheRepository::getImageUrl($v['cover']);
  431. if (!empty($v['user'])) {
  432. $v['user']['avatar'] = !empty($v['user']['avatar']) ? M3u8CacheRepository::getImageUrl($v['user']['avatar']) : '';
  433. }
  434. // if (!empty($v['user'])) {
  435. // $v['user']['is_focus'] = $relationRepo->userIsFocusOtherUser($userCode, $v['user']['code']);
  436. // }
  437. // $v['is_my_like'] = $relationRepo->userIsLikeVideo($userCode, $v['id']);
  438. $arrData[] = ['type' => 'v', 'video' => $v];
  439. if ($k != 0 && $adStep % $stepDelimiter == 0 && !empty($arrAds)) {
  440. $tmpArrPlay = $videoRepo->getRandAdFromAds($arrAds);
  441. $tmpArrPlay['cover'] = !empty($tmpArrPlay['cover']) ? M3u8CacheRepository::getImageUrl($tmpArrPlay['cover']) : '';
  442. if (!empty($tmpArrPlay['link'])) {
  443. $tmpArrPlay['link'] = M3u8CacheRepository::getLinkUrl($tmpArrPlay['link'], ['user_code' => $userCode]);
  444. }
  445. if (!empty($tmpArrPlay['play'])) {
  446. $tmpArrPlay['play'] = M3u8CacheRepository::getVideoInnerUrl($tmpArrPlay['play'], $userCode, $tmpArrPlay['id'], 'ad');
  447. }
  448. unset($tmpArrPlay['id']);
  449. $arrData[] = ['type' => 'a', 'video' => $tmpArrPlay];
  450. }
  451. $adStep++;
  452. }
  453. $lists['data'] = $arrData;
  454. }
  455. return json_success($lists);
  456. }
  457. }