Modules_Manage_Controllers_VideoController.proxy.php 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. <?php
  2. /**
  3. * 视频相关
  4. * @author x.b
  5. *
  6. */
  7. declare (strict_types=1);
  8. namespace Modules\Manage\Controllers;
  9. use App\Jobs\ClearAllLastestPagesCacheJob;
  10. use App\Jobs\HomeVideoInitJob;
  11. use App\Jobs\SendMessageToUserJob;
  12. use App\Jobs\VideoAutoCommentJob;
  13. use App\Model\TypeVideoModel;
  14. use App\Model\UserBuyVideoModel;
  15. use App\Model\UserModel;
  16. use App\Model\VideoModel as Model;
  17. use App\Model\VideoModel;
  18. use App\Model\VideoPerfectModel;
  19. use App\Repositories\CreatorRepository;
  20. use App\Repositories\Service\CommonService;
  21. use App\Repositories\Service\QueueService;
  22. use App\Repositories\VideoRepository;
  23. use Carbon\Carbon;
  24. use Hyperf\DbConnection\Db;
  25. use Hyperf\Validation\Contract\ValidatorFactoryInterface;
  26. use Modules\Api\Services\VideoService;
  27. use App\Model\TypeModel;
  28. use App\Constants\CommonConstant;
  29. class VideoController extends BaseController
  30. {
  31. use \Hyperf\Di\Aop\ProxyTrait;
  32. use \Hyperf\Di\Aop\PropertyHandlerTrait;
  33. function __construct()
  34. {
  35. if (method_exists(parent::class, '__construct')) {
  36. parent::__construct(...func_get_args());
  37. }
  38. $this->__handlePropertyHandler(__CLASS__);
  39. }
  40. /**
  41. * 视频列表
  42. * @param ValidatorFactoryInterface $validatorFactory
  43. * @return mixed
  44. * @example param_json_data string:
  45. * {"handshake":"","data":{"page":1,"page_size":5,"order":"id","order_sort":"desc","search":{"is_home":"","type_id":"53","title":"","video_id":"","user_id":"","status":"","check":"","stime":"","otime":""}}}
  46. */
  47. public function list(ValidatorFactoryInterface $validatorFactory)
  48. {
  49. $inputData = $this->getJsonData();
  50. $rules = ['page' => 'required|int', 'page_size' => 'required|int'];
  51. $validator = $validatorFactory->make($inputData, $rules);
  52. if ($validator->fails()) {
  53. return json_fail($validator->errors()->first());
  54. }
  55. $page = $inputData['page'];
  56. $page_size = intval($inputData['page_size']);
  57. if ($page_size <= 0) {
  58. $page_size = 12;
  59. }
  60. if ($page_size > 100) {
  61. $page_size = CommonConstant::PAGE_SIZE;
  62. }
  63. $select = ['video.*', Db::raw("(select user.nick from user where user.code=video.uid) AS user_nick")];
  64. $model = Model::query();
  65. $order_key = isset($inputData['order']) ? $inputData['order'] : 'id';
  66. $order_value = isset($inputData['order_sort']) ? $inputData['order_sort'] : 'desc';
  67. if (!$order_key) {
  68. $order_key = 'id';
  69. //不要信任前端,他可能会传个空字符串过来!
  70. }
  71. if (!$order_value) {
  72. $order_value = 'desc';
  73. }
  74. // "type_id":"视频分类ID", "title":"视频名字", "video_id":"视频ID", "user_id":"用户ID", "status":"上架状态", "check":"审核状态","stime":"视频的上传开始时间", "otime":"视频的上传结束时间", "is_home":"是否为首页视频( 0-不是 1-是 ''-不过滤)"
  75. // 备注: mu字段没包含.m3u8就是没转码
  76. $search = isset($inputData['search']) ? $inputData['search'] : array();
  77. if ($search) {
  78. foreach ($search as $k => $v) {
  79. if (!strlen((string) $v)) {
  80. continue;
  81. }
  82. switch ($k) {
  83. case "is_home":
  84. $is_home_ids = VideoPerfectModel::query()->pluck('video_id');
  85. if ($v == '1') {
  86. $model->whereIn('id', $is_home_ids);
  87. } else {
  88. $model->whereNotIn('id', $is_home_ids);
  89. }
  90. break;
  91. case "type_id":
  92. $model->where('tv.' . $k, $v);
  93. $model->leftJoin('type_video as tv', 'video.id', '=', 'tv.video_id');
  94. break;
  95. case "category_alias_name":
  96. $model->whereHas('perfect', function ($q1) use($v) {
  97. $q1->where('category_alias_name', $v);
  98. });
  99. break;
  100. case "title":
  101. $model->where('video.' . $k, 'like', '%' . $v . '%');
  102. break;
  103. case "user_id":
  104. $model->where('video.uid', $v);
  105. break;
  106. case "video_id":
  107. $model->where('video.id', $v);
  108. break;
  109. case "stime":
  110. $model->where('video.created_at', '>=', Carbon::parse($v)->startOfDay()->toDateTimeString());
  111. break;
  112. case "otime":
  113. $model->where('video.created_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  114. break;
  115. case "online_otime":
  116. $model->where('video.online_at', '>=', Carbon::parse($v)->startOfDay()->toDateTimeString());
  117. break;
  118. case "online_stime":
  119. $model->where('video.online_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  120. break;
  121. case "player_type":
  122. $model->where('video.player_type', $v);
  123. break;
  124. default:
  125. $model->where('video.' . $k, $v);
  126. }
  127. }
  128. }
  129. $creatorRepo = make(CreatorRepository::class);
  130. $result = $model->select($select)->with(['category:type.id as type_id,type.title', 'perfect:id,video_id,category_alias_name'])->orderBy((string) $order_key, (string) $order_value)->paginate($page_size, ['*'], 'page', $page);
  131. $result = $result->toArray();
  132. if (!empty($result['data'])) {
  133. foreach ($result['data'] as &$v) {
  134. if ($v['pay_type'] == 2) {
  135. // 金币视频, 才走sql
  136. $v['buy_video_count'] = $creatorRepo->countVideoBuyer($v['id']);
  137. } else {
  138. $v['buy_video_count'] = 0;
  139. }
  140. }
  141. }
  142. //处理图片/视频路径
  143. // foreach ($result as $v) {
  144. // if (!$v->from) {
  145. // $v->cover = make(CommonService::class)->getImageUrl((string)$v->cover, true);
  146. // $v->smu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->smu);
  147. // $v->mu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->mu);
  148. // }
  149. // }
  150. return json_success($result);
  151. }
  152. /**
  153. * 删除 (假删)
  154. * @param ValidatorFactoryInterface $validatorFactory
  155. * @return mixed
  156. * @example param_json_data string: {"handshake":"","data":{"id":8}}
  157. */
  158. public function delete(ValidatorFactoryInterface $validatorFactory)
  159. {
  160. $inputData = $this->getJsonData();
  161. $rules = ['id' => 'required|int'];
  162. $validator = $validatorFactory->make($inputData, $rules);
  163. if ($validator->fails()) {
  164. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  165. return json_fail($validator->errors()->first());
  166. }
  167. $info = Model::query()->where('id', $inputData['id'])->first();
  168. if (!$info) {
  169. return json_fail('视频信息不存在');
  170. }
  171. $result = Model::query()->where('id', $inputData['id'])->delete();
  172. if (!$result) {
  173. return json_fail('删除失败');
  174. }
  175. // 清理最新视频分页缓存.
  176. dispatch_job(new ClearAllLastestPagesCacheJob());
  177. // 创建管理员日志
  178. $olditem = clone $info;
  179. $logSubject = "删除视频";
  180. $logSvalue = $olditem->id;
  181. $logDbData = ['after_items' => [], 'before_items' => [$olditem->toArray()]];
  182. $this->log($logSubject, $logSvalue, $logDbData);
  183. return json_success($result);
  184. }
  185. /**
  186. * 删除-批量 (假删)
  187. * @param ValidatorFactoryInterface $validatorFactory
  188. * @return mixed
  189. * @example param_json_data string: {"handshake":"","data":{"ids":"1,2,4"}}
  190. */
  191. public function deleteList(ValidatorFactoryInterface $validatorFactory)
  192. {
  193. $inputData = $this->getJsonData();
  194. $rules = ['ids' => 'required|string'];
  195. $validator = $validatorFactory->make($inputData, $rules);
  196. if ($validator->fails()) {
  197. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  198. return json_fail($validator->errors()->first());
  199. }
  200. $ids = $inputData['ids'];
  201. $_ids = explode(',', $ids);
  202. $ids_list = [];
  203. foreach ($_ids as $kk => $vv) {
  204. if (!$vv) {
  205. continue;
  206. }
  207. $ids_list[] = $vv;
  208. }
  209. if (!$ids_list) {
  210. return json_fail("操作失败,没有满足的视频ID");
  211. }
  212. $result = Model::query()->whereIn('id', $ids_list)->delete();
  213. if (!$result) {
  214. return json_fail('删除失败');
  215. }
  216. // 清理最新视频分页缓存.
  217. dispatch_job(new ClearAllLastestPagesCacheJob());
  218. // 创建管理员日志
  219. $logSubject = "批量删除视频,ids为:{$ids}";
  220. $logSvalue = '';
  221. $logDbData = ['after_items' => [], 'before_items' => [$ids_list]];
  222. return json_success($result);
  223. }
  224. /**
  225. * 回收站-列表 (强制过滤删除的视频)
  226. * @param ValidatorFactoryInterface $validatorFactory
  227. * @return mixed
  228. * @example param_json_data string:
  229. * {"handshake":"","data":{"page":1,"page_size":5,"order":"id","order_sort":"desc","search":{"type_id":"","title":"","video_id":"","user_id":"","status":"","check":"","stime":"","otime":""}}}
  230. */
  231. public function deleteHistoryList(ValidatorFactoryInterface $validatorFactory)
  232. {
  233. $inputData = $this->getJsonData();
  234. $rules = ['page' => 'required|int', 'page_size' => 'required|int'];
  235. $validator = $validatorFactory->make($inputData, $rules);
  236. if ($validator->fails()) {
  237. return json_fail($validator->errors()->first());
  238. }
  239. $page = $inputData['page'];
  240. $page_size = $inputData['page_size'];
  241. $select = ['video.*', Db::raw("(select user.nick from user where user.code=video.uid) AS user_nick")];
  242. //$model = Model::query(); //这样写法,是查询出deleted_at无值的数据
  243. $model = Model::query()->onlyTrashed();
  244. //注意:这样写,因需要查询出deleted_at有值的数据,
  245. $order_key = isset($inputData['order']) ? $inputData['order'] : 'id';
  246. $order_value = isset($inputData['order_sort']) ? $inputData['order_sort'] : 'desc';
  247. if (!$order_key) {
  248. $order_key = 'id';
  249. //不要信任前端,他可能会传个空字符串过来!
  250. }
  251. if (!$order_value) {
  252. $order_value = 'desc';
  253. }
  254. // "type_id":"视频分类ID", "title":"视频名字", "video_id":"视频ID", "user_id":"用户ID", "status":"上架状态", "check":"审核状态","stime":"视频的上传开始时间", "otime":"视频的上传结束时间"
  255. // 备注: mu字段没包含.m3u8就是没转码
  256. $search = isset($inputData['search']) ? $inputData['search'] : array();
  257. if ($search) {
  258. foreach ($search as $k => $v) {
  259. if (!strlen((string) $v)) {
  260. continue;
  261. }
  262. switch ($k) {
  263. case "type_id":
  264. $model->where('tv.' . $k, $v);
  265. $model->leftJoin('type_video as tv', 'video.id', '=', 'tv.video_id');
  266. break;
  267. case "title":
  268. $model->where('video.' . $k, 'like', $v . '%');
  269. break;
  270. case "user_id":
  271. $model->where('video.uid', $v);
  272. break;
  273. case "video_id":
  274. $model->where('video.id', $v);
  275. break;
  276. case "stime":
  277. $model->where('video.created_at', '>=', $v);
  278. break;
  279. case "otime":
  280. $model->where('video.created_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  281. break;
  282. default:
  283. $model->where('video.' . $k, $v);
  284. }
  285. }
  286. }
  287. $result = $model->select($select)->with(['category:type.id as type_id,type.title'])->orderBy((string) $order_key, (string) $order_value)->paginate($page_size, ['*'], 'page', $page);
  288. //处理图片/视频路径
  289. // foreach ($result as $v) {
  290. // if (!$v->from) {
  291. // $v->cover = make(CommonService::class)->getImageUrl((string)$v->cover, true);
  292. // $v->smu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->smu);
  293. // $v->mu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->mu);
  294. // }
  295. // }
  296. return json_success($result);
  297. }
  298. /**
  299. * 回收站-恢复(即取消删除)
  300. * @param ValidatorFactoryInterface $validatorFactory
  301. * @return mixed
  302. * @example param_json_data string: {"handshake":"","data":{"id":2}}
  303. */
  304. public function reset(ValidatorFactoryInterface $validatorFactory)
  305. {
  306. $inputData = $this->getJsonData();
  307. $rules = ['id' => 'required|int'];
  308. $validator = $validatorFactory->make($inputData, $rules);
  309. if ($validator->fails()) {
  310. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  311. return json_fail($validator->errors()->first());
  312. }
  313. $info = Db::table('video')->where('id', $inputData['id'])->first();
  314. if (!$info) {
  315. return json_fail('视频信息不存在');
  316. }
  317. $data = ['deleted_at' => null];
  318. $result = Db::table('video')->where('id', $inputData['id'])->update($data);
  319. /*
  320. $result = Model::query()
  321. ->where('id', $inputData['id'])
  322. ->restore(); // 这个写法可以设置为null, 框架提供的方法
  323. */
  324. if (!$result) {
  325. return json_fail('恢复失败');
  326. }
  327. // 创建管理员日志
  328. $olditem = clone $info;
  329. $olditem = json_decode(json_encode($olditem), true);
  330. $newitem = Model::query()->where('id', $inputData['id'])->first();
  331. $logSubject = "恢复视频,将已删除的视频ID:{$inputData['id']},进行恢复状态";
  332. $logSvalue = $inputData['id'];
  333. $logDbData = ['after_items' => [$newitem->toArray()], 'before_items' => [
  334. //$olditem->toArray(),
  335. $olditem,
  336. ]];
  337. $this->log($logSubject, $logSvalue, $logDbData);
  338. // 清理最新视频分页缓存.
  339. dispatch_job(new ClearAllLastestPagesCacheJob());
  340. return json_success($result);
  341. }
  342. /**
  343. * 首页视频管理-列表
  344. * @param ValidatorFactoryInterface $validatorFactory
  345. * @return mixed
  346. * @example param_json_data string:
  347. * {"handshake":"","data":{"page":1,"page_size":5,"order":"id","order_sort":"desc","search":{"title":"","video_id":"","user_id":"","stime":"","otime":""}}}
  348. */
  349. public function indexList(ValidatorFactoryInterface $validatorFactory)
  350. {
  351. $inputData = $this->getJsonData();
  352. $rules = ['page' => 'required|int', 'page_size' => 'required|int'];
  353. $validator = $validatorFactory->make($inputData, $rules);
  354. if ($validator->fails()) {
  355. return json_fail($validator->errors()->first());
  356. }
  357. $page = $inputData['page'];
  358. $page_size = $inputData['page_size'];
  359. $order_key = $inputData['order'] ?? "";
  360. $order_value = $inputData['order_sort'] ?? 'desc';
  361. switch ($order_key) {
  362. case "like":
  363. $order_key = 'video.like';
  364. //点赞量
  365. break;
  366. default:
  367. $order_key = 'video_perfect.id';
  368. }
  369. switch ($order_value) {
  370. case "asc":
  371. $order_value = 'asc';
  372. break;
  373. default:
  374. $order_value = 'desc';
  375. }
  376. $model = VideoPerfectModel::query();
  377. // "title":"视频名字", "video_id":"视频ID", "user_id":"用户ID", "stime":"首页视频添加-开始时间", "otime":"首页视频添加-结束时间"
  378. $search = isset($inputData['search']) ? $inputData['search'] : array();
  379. if ($search) {
  380. foreach ($search as $k => $v) {
  381. if (!strlen((string) $v)) {
  382. continue;
  383. }
  384. switch ($k) {
  385. case "title":
  386. $model->where('video.' . $k, 'like', "{$v}%");
  387. break;
  388. case "video_id":
  389. $model->where('video_perfect.' . $k, $v);
  390. break;
  391. case "user_id":
  392. $model->where('video.uid', $v);
  393. break;
  394. case "stime":
  395. $model->where('video_perfect.created_at', '>=', $v);
  396. break;
  397. case "otime":
  398. $model->where('video_perfect.created_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  399. break;
  400. default:
  401. }
  402. }
  403. }
  404. $select = ['video_perfect.id as video_perfect_id', 'video_perfect.created_at as video_perfect_created_at', 'video_perfect.video_id', 'video.*', Db::raw("(select user.nick from user where user.code=video.uid) AS user_nick")];
  405. $result = $model->select($select)->join('video', 'video.id', '=', 'video_perfect.video_id')->with(['category:type.id as type_id,type.title'])->orderBy((string) $order_key, (string) $order_value)->paginate($page_size, ['*'], 'page', $page);
  406. //处理图片/视频路径
  407. // foreach ($result as $v) {
  408. // if (!$v->from) {
  409. // $v->cover = make(CommonService::class)->getImageUrl((string)$v->cover, true);
  410. // $v->smu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->smu);
  411. // $v->mu = make(VideoService::class)->getPlayUrl((string)$v->from, (string)$v->mu);
  412. // }
  413. // }
  414. return json_success($result);
  415. }
  416. /**
  417. * 首页视频管理-删除[真删]
  418. * @param ValidatorFactoryInterface $validatorFactory
  419. * @return mixed
  420. * @example param_json_data string: {"handshake":"","data":{"video_id":"11"}}
  421. */
  422. public function indexDelete(ValidatorFactoryInterface $validatorFactory)
  423. {
  424. $inputData = $this->getJsonData();
  425. $rules = ['video_id' => 'required|string'];
  426. $validator = $validatorFactory->make($inputData, $rules);
  427. if ($validator->fails()) {
  428. return json_fail($validator->errors()->first());
  429. }
  430. $video_id = $inputData['video_id'];
  431. $info = VideoPerfectModel::query()->where('video_id', $video_id)->first();
  432. if (!$info) {
  433. return json_fail("此视频已从首页视频中删除,请勿重复操作");
  434. }
  435. $result = VideoPerfectModel::query()->where('video_id', $video_id)->delete();
  436. if (!$result) {
  437. return json_fail("操作失败");
  438. }
  439. // 创建管理员日志
  440. $old_items = clone $info;
  441. $logSubject = "删除首页视频,id为:{$video_id}";
  442. $logSvalue = $video_id;
  443. $logDbData = ['after_items' => [], 'before_items' => [$old_items->toArray()]];
  444. $this->log($logSubject, $logSvalue, $logDbData);
  445. // 清理最新视频分页缓存.
  446. dispatch_job(new ClearAllLastestPagesCacheJob());
  447. return json_success('', '操作成功');
  448. }
  449. /**
  450. * 首页视频管理-批量删除[真删]
  451. * @param ValidatorFactoryInterface $validatorFactory
  452. * @return mixed
  453. * @example param_json_data string: {"handshake":"","data":{"ids":"1,3,4"}}
  454. */
  455. public function indexDeleteMore(ValidatorFactoryInterface $validatorFactory)
  456. {
  457. $inputData = $this->getJsonData();
  458. $rules = ['ids' => 'required|string'];
  459. $validator = $validatorFactory->make($inputData, $rules);
  460. if ($validator->fails()) {
  461. return json_fail($validator->errors()->first());
  462. }
  463. $ids = $inputData['ids'];
  464. $_ids = explode(',', $ids);
  465. $ids_list = [];
  466. foreach ($_ids as $kk => $vv) {
  467. if (!$vv) {
  468. continue;
  469. }
  470. $ids_list[] = $vv;
  471. }
  472. if (!$ids_list) {
  473. return json_fail("操作失败,没有满足的视频ID");
  474. }
  475. $result = VideoPerfectModel::query()->whereIn('video_id', $ids_list)->delete();
  476. if (!$result) {
  477. return json_fail("操作失败");
  478. }
  479. // 创建管理员日志
  480. $logSubject = "批量删除首页视频,ids为:{$ids}";
  481. $logSvalue = '';
  482. $logDbData = ['after_items' => [], 'before_items' => [$ids_list]];
  483. $this->log($logSubject, $logSvalue, $logDbData);
  484. // 清理最新视频分页缓存.
  485. dispatch_job(new ClearAllLastestPagesCacheJob());
  486. return json_success('', '操作成功');
  487. }
  488. /**
  489. * 首页视频管理-批量添加
  490. * @param ValidatorFactoryInterface $validatorFactory
  491. * @return mixed
  492. * @example param_json_data string: {"handshake":"","data":{"ids":"1,2,3,4"}}
  493. */
  494. public function indexAdds(ValidatorFactoryInterface $validatorFactory)
  495. {
  496. $inputData = $this->getJsonData();
  497. $rules = ['ids' => 'required|string'];
  498. $validator = $validatorFactory->make($inputData, $rules);
  499. if ($validator->fails()) {
  500. return json_fail($validator->errors()->first());
  501. }
  502. $ids = $inputData['ids'];
  503. $_ids = explode(',', $ids);
  504. $check = VideoPerfectModel::query()->whereIn('video_id', $_ids)->get();
  505. $_ids_db = [];
  506. if ($check) {
  507. //过滤已添加的视频id
  508. foreach ($check as $k) {
  509. $_ids_db[] = $k->video_id;
  510. }
  511. }
  512. $data = [];
  513. foreach ($_ids as $kk => $vv) {
  514. if (!$vv) {
  515. continue;
  516. }
  517. if (in_array($vv, $_ids_db)) {
  518. continue;
  519. }
  520. $data[] = array('video_id' => $vv, 'created_at' => Carbon::now()->toDateTimeString(), 'updated_at' => Carbon::now()->toDateTimeString());
  521. }
  522. if (!$data) {
  523. return json_fail("这些视频已处理,请勿重复操作");
  524. }
  525. $result = VideoPerfectModel::query()->insert($data);
  526. if (!$result) {
  527. return json_fail("操作失败");
  528. }
  529. // 创建管理员日志
  530. $logSubject = "批量追加首页视频";
  531. $logSvalue = '';
  532. $logDbData = ['after_items' => [$data], 'before_items' => []];
  533. $this->log($logSubject, $logSvalue, $logDbData);
  534. // 清理最新视频分页缓存.
  535. dispatch_job(new ClearAllLastestPagesCacheJob());
  536. return json_success('', '操作成功');
  537. }
  538. /**
  539. * 审核
  540. * @author x.b
  541. * @param ValidatorFactoryInterface $validatorFactory
  542. * @return mixed
  543. * @example param_json_data string: {"handshake":"","data":{"video_id":7,"check":1}}
  544. */
  545. public function check(ValidatorFactoryInterface $validatorFactory)
  546. {
  547. $inputData = $this->getJsonData();
  548. $rules = ['video_id' => 'required|int', 'check' => 'required|in:1,2'];
  549. $validator = $validatorFactory->make($inputData, $rules);
  550. if ($validator->fails()) {
  551. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  552. return json_fail($validator->errors()->first());
  553. }
  554. $data = ['id' => $inputData['video_id'], 'check' => $inputData['check']];
  555. $data = action_data($data);
  556. $oldItem = VideoModel::query()->where('id', $inputData['video_id'])->first();
  557. if (!$oldItem) {
  558. return json_fail('视频不存在');
  559. }
  560. if ($inputData['check'] == 1 && strpos($oldItem->mu, '.mp4')) {
  561. //状态改为转码中
  562. $data['status'] = 2;
  563. //转码
  564. make(QueueService::class)->addShiftVideoJob(['path' => $oldItem->mu, 'table' => 'video', 'id' => $oldItem->id, 'update' => 'mu']);
  565. }
  566. $result = VideoModel::query()->where('id', $inputData['video_id'])->update($data);
  567. $newitem = VideoModel::query()->where('id', $inputData['video_id'])->first();
  568. // 创建管理员日志
  569. $logSubject = "审核视频";
  570. $logSvalue = $inputData['video_id'];
  571. $logDbData = ['after_items' => [$newitem->toArray()], 'before_items' => [$oldItem->toArray()]];
  572. $this->log($logSubject, $logSvalue, $logDbData);
  573. return json_success($result);
  574. }
  575. /**
  576. * 编辑(标示上架/下架)
  577. * @author x.b
  578. * @param ValidatorFactoryInterface $validatorFactory
  579. * @param string no $video_id 视频ID(内调此接口使用) - 非必传
  580. * @param string no $status 状态0-下架 1-上架(内调此接口使用)- 非必传
  581. * @return mixed 若是 内调时,返回bool
  582. * @example param_json_data string: {"handshake":"","data":{"video_id":7,"status":1}}
  583. */
  584. public function update(ValidatorFactoryInterface $validatorFactory, $video_id = '', $status = '')
  585. {
  586. $inputData = $this->getJsonData();
  587. $rules = ['video_id' => 'required|int', 'status' => 'required|in:1,2'];
  588. if (!$video_id) {
  589. $validator = $validatorFactory->make($inputData, $rules);
  590. if ($validator->fails()) {
  591. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  592. return json_fail($validator->errors()->first());
  593. }
  594. $is_self = 0;
  595. //是否为内调 0-不是 1-是
  596. } else {
  597. $inputData['video_id'] = $video_id;
  598. $inputData['status'] = $status;
  599. $is_self = 1;
  600. }
  601. $oldItem = VideoModel::query()->where('id', $inputData['video_id'])->first();
  602. if (!$oldItem) {
  603. return $is_self ? false : json_fail('视频不存在');
  604. }
  605. // if ($inputData['status'] == 1
  606. // &&
  607. // (
  608. // !strpos($oldItem->mu, '.m3u8')
  609. // ||
  610. // !strpos($oldItem->smu, '.m3u8')
  611. // )
  612. // ) {
  613. // return $is_self ? false : json_fail('视频还未转码');
  614. // }
  615. $data = ['status' => $inputData['status'], 'online_at' => date('Y-m-d H:i:s')];
  616. $result = VideoModel::query()->where('id', $inputData['video_id'])->update($data);
  617. // 同步沉余更新视频分类数据表
  618. $data2 = ['status' => $inputData['status']];
  619. $result = TypeVideoModel::query()->where('video_id', $inputData['video_id'])->update($data2);
  620. $newitem = VideoModel::query()->where('id', $inputData['video_id'])->first();
  621. // 创建管理员日志
  622. $logSubject = "上下架视频";
  623. $logSvalue = $inputData['video_id'];
  624. $logDbData = ['after_items' => [$newitem->toArray()], 'before_items' => [$oldItem->toArray()]];
  625. $this->log($logSubject, $logSvalue, $logDbData);
  626. if ($oldItem->status != $newitem->status) {
  627. // 清理最新视频分页缓存.
  628. dispatch_job(new ClearAllLastestPagesCacheJob());
  629. }
  630. return $is_self ? true : json_success($result);
  631. }
  632. /**
  633. * 批量上架 ( 特殊处理: 内调 依次 上架 接口)
  634. * @param ValidatorFactoryInterface $validatorFactory
  635. * @return mixed
  636. * @example param_json_data string: {"handshake":"","data":{"ids":"8,9,10"}}
  637. */
  638. public function setStatusUp(ValidatorFactoryInterface $validatorFactory)
  639. {
  640. $inputData = $this->getJsonData();
  641. $rules = ['ids' => 'required|string'];
  642. $validator = $validatorFactory->make($inputData, $rules);
  643. if ($validator->fails()) {
  644. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  645. return json_fail($validator->errors()->first());
  646. }
  647. $ids = $inputData['ids'];
  648. $_ids = explode(',', $ids);
  649. $ids_list = [];
  650. foreach ($_ids as $kk => $vv) {
  651. if (!$vv) {
  652. continue;
  653. }
  654. $ids_list[] = $vv;
  655. }
  656. if (!$ids_list) {
  657. return json_fail("操作失败,没有满足的视频ID");
  658. }
  659. $error_msg = "";
  660. foreach ($ids_list as $v) {
  661. $r = self::update($validatorFactory, $v, 1);
  662. if ($r === false) {
  663. $error_msg .= ' ' . $v;
  664. }
  665. }
  666. if ($error_msg) {
  667. return json_fail('', '操作失败,以下视频ID处理失败:' . $error_msg);
  668. } else {
  669. // 清理最新视频分页缓存.
  670. dispatch_job(new ClearAllLastestPagesCacheJob());
  671. return json_success('', '全部处理成功');
  672. }
  673. }
  674. /**
  675. * 批量下架
  676. * @param ValidatorFactoryInterface $validatorFactory
  677. * @return mixed
  678. * @example param_json_data string: {"handshake":"","data":{"ids":"8,9,10"}}
  679. */
  680. public function setStatusDown(ValidatorFactoryInterface $validatorFactory)
  681. {
  682. $inputData = $this->getJsonData();
  683. $rules = ['ids' => 'required|string'];
  684. $validator = $validatorFactory->make($inputData, $rules);
  685. if ($validator->fails()) {
  686. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  687. return json_fail($validator->errors()->first());
  688. }
  689. $ids = $inputData['ids'];
  690. $_ids = explode(',', $ids);
  691. $ids_list = [];
  692. foreach ($_ids as $kk => $vv) {
  693. if (!$vv) {
  694. continue;
  695. }
  696. $ids_list[] = $vv;
  697. }
  698. if (!$ids_list) {
  699. return json_fail("操作失败,没有满足的视频ID");
  700. }
  701. $data = [
  702. 'status' => 2,
  703. //2-下架 1-上架
  704. 'online_at' => Carbon::now()->toDateTimeString(),
  705. ];
  706. $result = VideoModel::query()->whereIn('id', $ids_list)->update($data);
  707. // 同步沉余更新视频分类数据表
  708. $data2 = ['status' => 0];
  709. $result = TypeVideoModel::query()->whereIn('video_id', $ids_list)->update($data2);
  710. // 创建管理员日志
  711. $logSubject = "批量下架视频,ids为:{$ids}";
  712. $logSvalue = '';
  713. $logDbData = ['after_items' => [], 'before_items' => [$ids_list]];
  714. $this->log($logSubject, $logSvalue, $logDbData);
  715. // 清理最新视频分页缓存.
  716. dispatch_job(new ClearAllLastestPagesCacheJob());
  717. return json_success($result);
  718. }
  719. /**
  720. * 添加/修改视频
  721. * @author x.b
  722. * @param ValidatorFactoryInterface $validatorFactory
  723. * @return mixed
  724. * @example param_json_data string: {"handshake":"","data":{"video_id":7,"title":1,"cover":'',"mu":'','like':1,"type_ids":'1,3,4',"coins":"10"}}
  725. */
  726. public function save(ValidatorFactoryInterface $validatorFactory)
  727. {
  728. $inputData = $this->getJsonData();
  729. if (isset($inputData['video_id'])) {
  730. $rules = [
  731. 'video_id' => 'int',
  732. 'title' => 'string',
  733. 'cover' => 'string',
  734. 'mu' => 'string',
  735. // 'like' => 'int',
  736. 'type_ids' => 'string',
  737. 'recommend_level' => 'int',
  738. 'pay_type' => 'required|int',
  739. ];
  740. } else {
  741. $rules = [
  742. 'video_id' => 'int',
  743. 'title' => 'required|string',
  744. 'cover' => 'required|string',
  745. 'mu' => 'required|string',
  746. // 'like' => 'int',
  747. 'type_ids' => 'string',
  748. 'recommend_level' => 'int',
  749. 'pay_type' => 'required|int',
  750. ];
  751. }
  752. $validator = $validatorFactory->make($inputData, $rules);
  753. if ($validator->fails()) {
  754. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  755. return json_fail($validator->errors()->first());
  756. }
  757. if (!$inputData['video_id']) {
  758. if (!$inputData['mu']) {
  759. return json_fail('请上传视频');
  760. }
  761. }
  762. $coins = intval(data_get($inputData, 'coins', 0));
  763. $payType = intval(data_get($inputData, 'pay_type', 1));
  764. if ($coins < 0) {
  765. return json_fail('请填写金币');
  766. }
  767. $data = [
  768. 'title' => $inputData['title'] ?? '',
  769. 'cover' => $inputData['cover'] ?? '',
  770. 'mu' => $inputData['mu'] ?? '',
  771. // 'like' => $inputData['like'],
  772. 'pay_type' => $payType,
  773. 'coins' => $coins,
  774. //金币
  775. 'uid' => $inputData['uid'] ?? '',
  776. //视频表uid 即用户邀请码 (微啪-非必传,官方视频绑定为 DFZUAR ),抖音-约会版 必传字段
  777. 'recommend_level' => isset($inputData['recommend_level']) ? intval($inputData['recommend_level']) : 0,
  778. ];
  779. /*if ($data['uid']) {
  780. $check = UserModel::query()
  781. ->select(['id'])
  782. ->where('code', $data['uid'])
  783. ->first();
  784. if (!$check) {
  785. return json_fail('请填写正确的用户邀请码');
  786. }
  787. }*/
  788. $newStrTags = '';
  789. $newArrTags = [];
  790. $create = action_data($data);
  791. if ($inputData['video_id']) {
  792. $oldItem = Model::query()->where('id', $inputData['video_id'])->first();
  793. if (!$oldItem) {
  794. return json_fail('视频不存在');
  795. }
  796. //判断分类
  797. if ($inputData['type_ids']) {
  798. $ids = explode(',', $inputData['type_ids']);
  799. foreach ($ids as $k => $id) {
  800. $typeObj = TypeModel::query()->where(['id' => $id])->first();
  801. if (!empty($typeObj)) {
  802. $newArrTags[] = $typeObj->title;
  803. }
  804. $type[$k] = ['type_id' => $id, 'video_id' => $inputData['video_id']];
  805. }
  806. }
  807. if (isset($type)) {
  808. TypeVideoModel::query()->where('video_id', $inputData['video_id'])->delete();
  809. TypeVideoModel::query()->insert($type);
  810. }
  811. if (!empty($newArrTags)) {
  812. $newStrTags = implode(',', $newArrTags);
  813. $create['tags'] = $newStrTags;
  814. } else {
  815. $create['tags'] = '';
  816. }
  817. $result = Model::query()->where('id', $inputData['video_id'])->update($create);
  818. $newitem = Model::query()->where('id', $inputData['video_id'])->first();
  819. // 创建管理员日志
  820. $logSubject = "修改视频";
  821. $logSvalue = $inputData['video_id'];
  822. $logDbData = ['after_items' => [$newitem->toArray()], 'before_items' => [$oldItem->toArray()]];
  823. $this->log($logSubject, $logSvalue, $logDbData);
  824. if ($oldItem->status != $newitem->status) {
  825. // 清理最新视频分页缓存.
  826. dispatch_job(new ClearAllLastestPagesCacheJob());
  827. }
  828. } else {
  829. if ($inputData['type_ids']) {
  830. $ids = explode(',', $inputData['type_ids']);
  831. foreach ($ids as $k => $id) {
  832. $typeObj = TypeModel::query()->where(['id' => $id])->first();
  833. if (!empty($typeObj)) {
  834. $newArrTags[] = $typeObj->title;
  835. }
  836. $type[$k] = ['type_id' => $id, 'video_id' => $inputData['video_id']];
  837. }
  838. }
  839. if (!empty($newArrTags)) {
  840. $newStrTags = implode(',', $newArrTags);
  841. $create['tags'] = $newStrTags;
  842. } else {
  843. $create['tags'] = '';
  844. }
  845. $result = Model::query()->create($create);
  846. if (!$result) {
  847. return json_fail('创建失败');
  848. }
  849. if (isset($type)) {
  850. TypeVideoModel::query()->insert($type);
  851. }
  852. // 创建管理员日志
  853. $logSubject = "添加视频";
  854. $logSvalue = $result->id;
  855. $logDbData = ['after_items' => [$result->toArray()], 'before_items' => []];
  856. $this->log($logSubject, $logSvalue, $logDbData);
  857. // 清理最新视频分页缓存.
  858. dispatch_job(new ClearAllLastestPagesCacheJob());
  859. }
  860. return json_success($result);
  861. }
  862. /**
  863. * 首页视频发布
  864. * @author x.b
  865. * @return mixed
  866. */
  867. public function home()
  868. {
  869. $video_ids = VideoPerfectModel::query()->pluck('video_id')->all();
  870. $count = count($video_ids) / 5;
  871. //总条数
  872. if ($count < 20) {
  873. return json_fail('视频至少添加100个,当前' . count($video_ids) . '个');
  874. }
  875. $result = make(QueueService::class)->addHomeVideoJob(['video_ids' => $video_ids]);
  876. // 创建管理员日志
  877. $logSubject = "发布首页视频";
  878. $logSvalue = 0;
  879. $logDbData = ['after_items' => [[]], 'before_items' => [$video_ids]];
  880. $this->log($logSubject, $logSvalue, $logDbData);
  881. return json_success($result);
  882. }
  883. /**
  884. * 首页视频桶缓存初始化.
  885. * @return mixed
  886. */
  887. public function homeInit()
  888. {
  889. dispatch_job(new HomeVideoInitJob());
  890. $logSubject = "首页视频桶缓存初始化";
  891. $logSvalue = 0;
  892. $logDbData = ['after_items' => [[]], 'before_items' => []];
  893. $this->log($logSubject, $logSvalue, $logDbData);
  894. return json_success(['result' => 'success']);
  895. }
  896. /**
  897. * 硬删除,用于回收站内.
  898. * @return mixed
  899. */
  900. public function hardDelete()
  901. {
  902. $validatorFactory = make(ValidatorFactoryInterface::class);
  903. $inputData = $this->getJsonData();
  904. $rules = ['ids' => 'required|array'];
  905. $validator = $validatorFactory->make($inputData, $rules);
  906. if ($validator->fails()) {
  907. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  908. return json_fail($validator->errors()->first());
  909. }
  910. $ids = data_get($inputData, 'ids', []);
  911. $ids = array_filter($ids);
  912. $ids = array_unique($ids);
  913. if (empty($ids)) {
  914. return json_fail('请选择视频');
  915. }
  916. $newIds = [];
  917. $items = VideoModel::query()->withTrashed()->whereIn('id', $ids)->get(['id', 'deleted_at']);
  918. if ($items->isNotEmpty()) {
  919. foreach ($items as $v) {
  920. if (is_null($v->deleted_at)) {
  921. return json_fail($v->id . ', 非回收站视频,不能完整执行硬删除操作');
  922. break;
  923. } else {
  924. $newIds[] = $v->id;
  925. }
  926. }
  927. }
  928. if (!empty($newIds)) {
  929. $videoRepo = make(VideoRepository::class);
  930. $videoRepo->hardDelete($newIds);
  931. } else {
  932. return json_fail('视频选择有误');
  933. }
  934. return json_success(['result' => 'success']);
  935. }
  936. /**
  937. * 审核
  938. * @return mixed
  939. */
  940. public function changeCheck()
  941. {
  942. $validatorFactory = make(ValidatorFactoryInterface::class);
  943. $inputData = $this->getJsonData();
  944. $rules = ['id' => 'required|int', 'target_check' => 'required|int', 'reject_reason' => 'nullable'];
  945. $validator = $validatorFactory->make($inputData, $rules);
  946. if ($validator->fails()) {
  947. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  948. return json_fail($validator->errors()->first());
  949. }
  950. $videoRepo = make(VideoRepository::class);
  951. $targetCheck = intval(data_get($inputData, 'target_check', 0));
  952. $obj = $videoRepo->find($inputData['id'], ['id', 'title', 'status', 'type', 'check', 'reject_reason', 'updated_at', 'created_at', 'uid', 'online_at']);
  953. if (empty($obj)) {
  954. return json_fail('对象不存在');
  955. }
  956. $rejectReason = data_get($inputData, 'reject_reason', '');
  957. if ($obj->check == $targetCheck) {
  958. return json_fail('前后状态无变化');
  959. }
  960. $creatorRepo = make(CreatorRepository::class);
  961. $creatorObj = $creatorRepo->detail($obj->uid);
  962. $videoTitle = mb_substr($obj->title, 0, 30);
  963. $msgSubjct = '恭喜您,视频【' . $videoTitle . '】审核通过.';
  964. $msgContent = '您可以分享本APP给微信、qq群里的朋友,收益越大.';
  965. $obj->reject_reason = '';
  966. if ($targetCheck == 2) {
  967. $obj->reject_reason = $rejectReason;
  968. $obj->status = 2;
  969. $msgSubjct = '视频【' . $videoTitle . '】未通过审核';
  970. $msgContent = '拒绝原因:' . $rejectReason . ', 若有异议,请联系客服!';
  971. } elseif ($targetCheck == 1) {
  972. $obj->status = 1;
  973. //审核通过就直接上架.
  974. $obj->online_at = Carbon::now()->toDateTimeString();
  975. // 上架时间
  976. $jobParams = ['video_id' => $obj->id, 'type' => $obj->type, 'status' => 1, 'check' => $targetCheck];
  977. // 异步自动增加评论和点赞
  978. dispatch_job(new VideoAutoCommentJob($jobParams));
  979. }
  980. $obj->check = $targetCheck;
  981. $saveStatus = $obj->save();
  982. if ($saveStatus && !empty($creatorObj)) {
  983. $jobParams = ['from_type' => 'sys', 'receive_uid' => $obj->uid, 'subject' => $msgSubjct, 'content' => $msgContent];
  984. // 异步发送通知站内消息
  985. dispatch_job(new SendMessageToUserJob($jobParams));
  986. $creatorRepo->checkUpgrade0to1($creatorObj);
  987. }
  988. return json_success(['result' => 'success']);
  989. }
  990. /**
  991. * 批量审核
  992. * @return mixed
  993. */
  994. public function batchChangeCheck()
  995. {
  996. $validatorFactory = make(ValidatorFactoryInterface::class);
  997. $inputData = $this->getJsonData();
  998. $rules = ['ids' => 'required', 'target_check' => 'required|int'];
  999. $validator = $validatorFactory->make($inputData, $rules);
  1000. if ($validator->fails()) {
  1001. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  1002. return json_fail($validator->errors()->first());
  1003. }
  1004. $videoRepo = make(VideoRepository::class);
  1005. $targetCheck = intval(data_get($inputData, 'target_check', 0));
  1006. $arrIds = [];
  1007. if (is_string($inputData['ids'])) {
  1008. $arrIds = explode(',', $inputData['ids']);
  1009. } else {
  1010. $arrIds = $inputData['ids'];
  1011. }
  1012. $rejectReason = '您上传的视频不符合要求';
  1013. if (!empty($arrIds)) {
  1014. $creatorRepo = make(CreatorRepository::class);
  1015. foreach ($arrIds as $id) {
  1016. $obj = $videoRepo->find($id, ['id', 'title', 'status', 'type', 'check', 'reject_reason', 'updated_at', 'created_at', 'uid', 'online_at']);
  1017. if (empty($obj)) {
  1018. continue;
  1019. }
  1020. if ($obj->check == $targetCheck) {
  1021. continue;
  1022. }
  1023. if ($obj->status == 2 && $obj->check == 0) {
  1024. // 未审核的条件
  1025. $creatorObj = $creatorRepo->detail($obj->uid);
  1026. $videoTitle = mb_substr($obj->title, 0, 30);
  1027. $msgSubjct = '恭喜您,视频【' . $videoTitle . '】审核通过.';
  1028. $msgContent = '您可以分享本APP给微信、qq群里的朋友,收益越大.';
  1029. $obj->reject_reason = '';
  1030. if ($targetCheck == 2) {
  1031. $obj->reject_reason = $rejectReason;
  1032. $obj->status = 2;
  1033. $msgSubjct = '视频【' . $videoTitle . '】未通过审核';
  1034. $msgContent = '拒绝原因:' . $rejectReason . ', 若有异议,请联系客服!';
  1035. } elseif ($targetCheck == 1) {
  1036. $obj->status = 1;
  1037. //审核通过就直接上架.
  1038. $obj->online_at = Carbon::now()->toDateTimeString();
  1039. // 上架时间
  1040. $jobParams = ['video_id' => $obj->id, 'type' => $obj->type, 'status' => 1, 'check' => $targetCheck];
  1041. // 异步自动增加评论和点赞
  1042. dispatch_job(new VideoAutoCommentJob($jobParams));
  1043. }
  1044. $obj->check = $targetCheck;
  1045. $saveStatus = $obj->save();
  1046. if ($saveStatus && !empty($creatorObj)) {
  1047. $jobParams = ['from_type' => 'sys', 'receive_uid' => $obj->uid, 'subject' => $msgSubjct, 'content' => $msgContent];
  1048. // 异步发送通知站内消息
  1049. dispatch_job(new SendMessageToUserJob($jobParams));
  1050. $creatorRepo->checkUpgrade0to1($creatorObj);
  1051. }
  1052. }
  1053. }
  1054. }
  1055. return json_success(['result' => 'success']);
  1056. }
  1057. }