From 734527e8c702dfd52dd77d043d429e220f433f9b Mon Sep 17 00:00:00 2001 From: make Date: Sat, 29 Nov 2025 22:53:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E8=8C=85=E5=8F=B0=E6=92=AD?= =?UTF-8?q?=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/.example.env | 4 + code/app/task/crawler/douban/Scheduler.php | 4 +- .../crawler/douban/page/VideoInfoPage.php | 102 ++++++++++++--- .../crawler/fengchao/page/VideoInfoPage.php | 94 ++++++++++++-- code/app/task/crawler/maotai/Scheduler.php | 4 +- .../crawler/maotai/page/VideoInfoPage.php | 116 +++++++++++++++--- .../crawler/wuxian/page/VideoInfoPage.php | 96 +++++++++++++-- .../crawler/youzhi/page/VideoInfoPage.php | 95 ++++++++++++-- code/config/video.php | 11 ++ code/public/public/video/common.js | 70 ++++++++--- doc/mongodb.md | 21 ++++ 11 files changed, 532 insertions(+), 85 deletions(-) create mode 100644 code/config/video.php diff --git a/code/.example.env b/code/.example.env index e12b7e5..9fcd80a 100644 --- a/code/.example.env +++ b/code/.example.env @@ -54,6 +54,10 @@ VIEW_TPL_CACHE = false VIEW_DATA_CACHE = false VIEW_DATA_CACHE_DRIVER = redis +# VIDEO +DEFAULT_LINE = maotai +TASK_TEST = true + # PROXY PROXY_STATUS = true # PROXY_CODE = XIONGMAO diff --git a/code/app/task/crawler/douban/Scheduler.php b/code/app/task/crawler/douban/Scheduler.php index 0edc116..7a7eeab 100644 --- a/code/app/task/crawler/douban/Scheduler.php +++ b/code/app/task/crawler/douban/Scheduler.php @@ -112,7 +112,9 @@ class Scheduler } $intTotalPage = $arrCategory['total_page']; - // $intTotalPage = 2 ; // test + if(config("video.task_test")){ + $intTotalPage = 2 ; // test + } $arrFilter = []; for ($intStartPage = 1; $intStartPage <= $intTotalPage; $intStartPage++) { diff --git a/code/app/task/crawler/douban/page/VideoInfoPage.php b/code/app/task/crawler/douban/page/VideoInfoPage.php index 8ee48e4..e3af309 100644 --- a/code/app/task/crawler/douban/page/VideoInfoPage.php +++ b/code/app/task/crawler/douban/page/VideoInfoPage.php @@ -66,37 +66,80 @@ class VideoInfoPage extends BasePage { if (empty($this->arrVideo)) { - $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = $arrVideo['list'][0] ?? []; + // // 如果结构不正确 → 返回空数组 + // if (!$arrVideo) { + // return []; + // } + + // // 2. 检查播放地址 + // $strPlayUrl = $arrVideo['vod_play_url'] ?? null; + + // // 2. 判断是否有播放地址 + // if (empty($arrVideo['vod_play_url'])) { + // // 无播放地址 → 丢弃该数据 + // return []; + // } + + // unset($arrVideo['vod_play_url']); + + // $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // $arrPlayUrl = explode('$', $arrPlayUrl); + + // $arrPlayUrl = array_filter($arrPlayUrl); + + // $arrPlayUrl = array_chunk($arrPlayUrl, 2); + // foreach ($arrPlayUrl as $intKey => $arrVal) { + // $strUrl = $arrVal[1] ?? ''; + // // *** 过滤掉不是 m3u8 的链接 *** + // if (!str_ends_with($strUrl, '.m3u8')) { + // continue; + // } + // $arrPlayUrl[$intKey] = [ + // 'name' => $arrVal[0], + // 'url' => $strUrl, + // ]; + // } + + $arrVideo = json_decode($this->getContent(), true); $arrVideo = $arrVideo['list'][0] ?? []; // 如果结构不正确 → 返回空数组 if (!$arrVideo) { return []; } - // 2. 检查播放地址 $strPlayUrl = $arrVideo['vod_play_url'] ?? null; - // 2. 判断是否有播放地址 if (empty($arrVideo['vod_play_url'])) { // 无播放地址 → 丢弃该数据 return []; } - unset($arrVideo['vod_play_url']); - + // 替换分隔符 $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // 拆成数组 $arrPlayUrl = explode('$', $arrPlayUrl); - - $arrPlayUrl = array_filter($arrPlayUrl); - + // 清理空值 + $arrPlayUrl = array_filter(array_map('trim', $arrPlayUrl)); + // 转成二维数组:[[name,url], [name,url], ...] $arrPlayUrl = array_chunk($arrPlayUrl, 2); - foreach ($arrPlayUrl as $intKey => $arrVal) { - $arrPlayUrl[$intKey] = [ - 'name' => $arrVal[0], - 'url' => $arrVal[1] ?? $arrVal[0], + // 最终结构 + $cleanPlayUrl = []; + foreach ($arrPlayUrl as $pair) { + $name = $pair[0] ?? ''; + $url = $pair[1] ?? ''; + // *** 过滤掉不是 m3u8 的链接 *** + if (!str_ends_with($url, '.m3u8')) { + continue; + } + $cleanPlayUrl[] = [ + 'name' => $name, + 'url' => $url, ]; } + $arrPlayUrl = $cleanPlayUrl; $arrVideo['vod_actor'] = trim($arrVideo['vod_actor']); $arrVideo['vod_director'] = trim($arrVideo['vod_director']); @@ -182,18 +225,47 @@ class VideoInfoPage extends BasePage $arrExistsVideo = $this->getVideoModel()->findOne(['v_name' => $arrPageVideo['v_name']], $this->arrOptions); if ($arrExistsVideo) { - + $arrExistsVideo = (array) $arrExistsVideo; + // 数据库里的旧播放源 + $oldPlayUrl = $arrExistsVideo['v_play_url'] ?? []; + + // 本次抓取的新播放源(可能不完整) + $newPagePlayUrl = $arrPageVideo['v_play_url'] ?? []; + + // 合并新老线路(新覆盖旧) + $mergedPlayUrl = array_merge($oldPlayUrl, $newPagePlayUrl); + + // 构造一个重新排序的结构 + $sortedPlayUrl = []; + + // 默认线路 + $strDefaultLine = config("video.default_line"); + + // 1. maotai 优先 + if (!empty($mergedPlayUrl[$strDefaultLine])) { + $sortedPlayUrl[$strDefaultLine] = $mergedPlayUrl[$strDefaultLine]; + } + + // 2. 其他线路顺序不变 + foreach ($mergedPlayUrl as $source => $value) { + if ($source !== $strDefaultLine) { + $sortedPlayUrl[$source] = $value; + } + } + + // 更新数据 $arrUpdate = [ 'updated_at' => new \MongoDB\BSON\UTCDateTime(), - 'v_play_url.douban' => $arrPageVideo['v_play_url']['douban'], + 'v_play_url' => $sortedPlayUrl, ]; $this->getVideoModel()->updateOne( ['v_name' => $arrPageVideo['v_name']], - ['$set' => $arrUpdate], + ['$set' => $arrUpdate] ); + $this->strPicLocalPath = $arrExistsVideo['v_pic']; } else { diff --git a/code/app/task/crawler/fengchao/page/VideoInfoPage.php b/code/app/task/crawler/fengchao/page/VideoInfoPage.php index 683439c..35994ab 100644 --- a/code/app/task/crawler/fengchao/page/VideoInfoPage.php +++ b/code/app/task/crawler/fengchao/page/VideoInfoPage.php @@ -66,22 +66,65 @@ class VideoInfoPage extends BasePage { if (empty($this->arrVideo)) { + // $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = $arrVideo['list'][0]; + // // print_r($arrVideo); + + // $strPlayUrl = $arrVideo['vod_play_url']; + // unset($arrVideo['vod_play_url']); + + // $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // $arrPlayUrl = explode('$', $arrPlayUrl); + // $arrPlayUrl = array_chunk($arrPlayUrl, 2); + // foreach ($arrPlayUrl as $intKey => $arrVal) { + // $strUrl = $arrVal[1] ?? ''; + // // *** 过滤掉不是 m3u8 的链接 *** + // if (!str_ends_with($strUrl, '.m3u8')) { + // continue; + // } + // $arrPlayUrl[$intKey] = [ + // 'name' => $arrVal[0], + // 'url' => $strUrl, + // ]; + // } + $arrVideo = json_decode($this->getContent(), true); - $arrVideo = $arrVideo['list'][0]; - // print_r($arrVideo); - - $strPlayUrl = $arrVideo['vod_play_url']; + $arrVideo = $arrVideo['list'][0] ?? []; + // 如果结构不正确 → 返回空数组 + if (!$arrVideo) { + return []; + } + // 2. 检查播放地址 + $strPlayUrl = $arrVideo['vod_play_url'] ?? null; + // 2. 判断是否有播放地址 + if (empty($arrVideo['vod_play_url'])) { + // 无播放地址 → 丢弃该数据 + return []; + } unset($arrVideo['vod_play_url']); - + // 替换分隔符 $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // 拆成数组 $arrPlayUrl = explode('$', $arrPlayUrl); + // 清理空值 + $arrPlayUrl = array_filter(array_map('trim', $arrPlayUrl)); + // 转成二维数组:[[name,url], [name,url], ...] $arrPlayUrl = array_chunk($arrPlayUrl, 2); - foreach ($arrPlayUrl as $intKey => $arrVal) { - $arrPlayUrl[$intKey] = [ - 'name' => $arrVal[0], - 'url' => $arrVal[1] ?? $arrVal[0], + // 最终结构 + $cleanPlayUrl = []; + foreach ($arrPlayUrl as $pair) { + $name = $pair[0] ?? ''; + $url = $pair[1] ?? ''; + // *** 过滤掉不是 m3u8 的链接 *** + if (!str_ends_with($url, '.m3u8')) { + continue; + } + $cleanPlayUrl[] = [ + 'name' => $name, + 'url' => $url, ]; } + $arrPlayUrl = $cleanPlayUrl; $arrVideo['vod_actor'] = trim($arrVideo['vod_actor']); $arrVideo['vod_director'] = trim($arrVideo['vod_director']); @@ -170,15 +213,44 @@ class VideoInfoPage extends BasePage $arrExistsVideo = (array) $arrExistsVideo; + // 数据库里的旧播放源 + $oldPlayUrl = $arrExistsVideo['v_play_url'] ?? []; + + // 本次抓取的新播放源(可能不完整) + $newPagePlayUrl = $arrPageVideo['v_play_url'] ?? []; + + // 合并新老线路(新覆盖旧) + $mergedPlayUrl = array_merge($oldPlayUrl, $newPagePlayUrl); + + // 构造一个重新排序的结构 + $sortedPlayUrl = []; + + // 默认线路 + $strDefaultLine = config("video.default_line"); + + // 1. maotai 优先 + if (!empty($mergedPlayUrl[$strDefaultLine])) { + $sortedPlayUrl[$strDefaultLine] = $mergedPlayUrl[$strDefaultLine]; + } + + // 2. 其他线路顺序不变 + foreach ($mergedPlayUrl as $source => $value) { + if ($source !== $strDefaultLine) { + $sortedPlayUrl[$source] = $value; + } + } + + // 更新数据 $arrUpdate = [ 'updated_at' => new \MongoDB\BSON\UTCDateTime(), - 'v_play_url.fengchao' => $arrPageVideo['v_play_url']['fengchao'], + 'v_play_url' => $sortedPlayUrl, ]; $this->getVideoModel()->updateOne( ['v_name' => $arrPageVideo['v_name']], - ['$set' => $arrUpdate], + ['$set' => $arrUpdate] ); + $this->strPicLocalPath = $arrExistsVideo['v_pic']; } else { diff --git a/code/app/task/crawler/maotai/Scheduler.php b/code/app/task/crawler/maotai/Scheduler.php index 359de02..850dce0 100644 --- a/code/app/task/crawler/maotai/Scheduler.php +++ b/code/app/task/crawler/maotai/Scheduler.php @@ -113,7 +113,9 @@ class Scheduler $intTotalPage = $arrCategory['total_page']; - // $intTotalPage = 2 ; // test + if(config("video.task_test")){ + $intTotalPage = 2 ; // test + } $arrFilter = []; for ($intStartPage = 1; $intStartPage <= $intTotalPage; $intStartPage++) { diff --git a/code/app/task/crawler/maotai/page/VideoInfoPage.php b/code/app/task/crawler/maotai/page/VideoInfoPage.php index 88b1710..f8ed94b 100644 --- a/code/app/task/crawler/maotai/page/VideoInfoPage.php +++ b/code/app/task/crawler/maotai/page/VideoInfoPage.php @@ -66,25 +66,69 @@ class VideoInfoPage extends BasePage { if (empty($this->arrVideo)) { + // $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = $arrVideo['list'][0]; + // // print_r($arrVideo); + + // $strPlayUrl = $arrVideo['vod_play_url']; + // unset($arrVideo['vod_play_url']); + + // $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // $arrPlayUrl = explode('$', $arrPlayUrl); + + // $arrPlayUrl = array_filter($arrPlayUrl); + // $arrPlayUrl = array_chunk($arrPlayUrl, 2); + // foreach ($arrPlayUrl as $intKey => $arrVal) { + // $strUrl = $arrVal[1] ?? ''; + // // *** 过滤掉不是 m3u8 的链接 *** + // if (!str_ends_with($strUrl, '.m3u8')) { + // continue; + // } + // $arrPlayUrl[$intKey] = [ + // 'name' => $arrVal[0], + // 'url' => $strUrl, + // ]; + // } + $arrVideo = json_decode($this->getContent(), true); - $arrVideo = $arrVideo['list'][0]; - // print_r($arrVideo); - - $strPlayUrl = $arrVideo['vod_play_url']; + $arrVideo = $arrVideo['list'][0] ?? []; + // 如果结构不正确 → 返回空数组 + if (!$arrVideo) { + return []; + } + // 2. 检查播放地址 + $strPlayUrl = $arrVideo['vod_play_url'] ?? null; + // 2. 判断是否有播放地址 + if (empty($arrVideo['vod_play_url'])) { + // 无播放地址 → 丢弃该数据 + return []; + } unset($arrVideo['vod_play_url']); - + // 替换分隔符 $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // 拆成数组 $arrPlayUrl = explode('$', $arrPlayUrl); - - $arrPlayUrl = array_filter($arrPlayUrl); - + // 清理空值 + $arrPlayUrl = array_filter(array_map('trim', $arrPlayUrl)); + // 转成二维数组:[[name,url], [name,url], ...] $arrPlayUrl = array_chunk($arrPlayUrl, 2); - foreach ($arrPlayUrl as $intKey => $arrVal) { - $arrPlayUrl[$intKey] = [ - 'name' => $arrVal[0], - 'url' => $arrVal[1] ?? $arrVal[0], + // 最终结构 + $cleanPlayUrl = []; + foreach ($arrPlayUrl as $pair) { + $name = $pair[0] ?? ''; + $url = $pair[1] ?? ''; + // *** 过滤掉不是 m3u8 的链接 *** + if (!str_ends_with($url, '.m3u8')) { + continue; + } + $cleanPlayUrl[] = [ + 'name' => $name, + 'url' => $url, ]; } + $arrPlayUrl = $cleanPlayUrl; + + $arrVideo['vod_actor'] = trim($arrVideo['vod_actor']); $arrVideo['vod_director'] = trim($arrVideo['vod_director']); @@ -171,18 +215,62 @@ class VideoInfoPage extends BasePage if ($arrExistsVideo) { + // $arrExistsVideo = (array) $arrExistsVideo; + + // $arrUpdate = [ + // 'updated_at' => new \MongoDB\BSON\UTCDateTime(), + // 'v_play_url.maotai' => $arrPageVideo['v_play_url']['maotai'], + // ]; + + // $this->getVideoModel()->updateOne( + // ['v_name' => $arrPageVideo['v_name']], + // ['$set' => $arrUpdate], + // ); + // $this->strPicLocalPath = $arrExistsVideo['v_pic']; + $arrExistsVideo = (array) $arrExistsVideo; + // 数据库里的旧播放源 + $oldPlayUrl = $arrExistsVideo['v_play_url'] ?? []; + + // 本次抓取的新播放源(可能不完整) + $newPagePlayUrl = $arrPageVideo['v_play_url'] ?? []; + + // 合并新老线路(新覆盖旧) + $mergedPlayUrl = array_merge($oldPlayUrl, $newPagePlayUrl); + + // 构造一个重新排序的结构 + $sortedPlayUrl = []; + + // 默认线路 + $strDefaultLine = config("video.default_line"); + + // 1. maotai 优先 + if (!empty($mergedPlayUrl[$strDefaultLine])) { + $sortedPlayUrl[$strDefaultLine] = $mergedPlayUrl[$strDefaultLine]; + } + + // 2. 其他线路顺序不变 + foreach ($mergedPlayUrl as $source => $value) { + if ($source !== $strDefaultLine) { + $sortedPlayUrl[$source] = $value; + } + } + + // 更新数据 $arrUpdate = [ 'updated_at' => new \MongoDB\BSON\UTCDateTime(), - 'v_play_url.maotai' => $arrPageVideo['v_play_url']['maotai'], + 'v_play_url' => $sortedPlayUrl, ]; $this->getVideoModel()->updateOne( ['v_name' => $arrPageVideo['v_name']], - ['$set' => $arrUpdate], + ['$set' => $arrUpdate] ); + $this->strPicLocalPath = $arrExistsVideo['v_pic']; + + } else { $arrInsertVideo = [ diff --git a/code/app/task/crawler/wuxian/page/VideoInfoPage.php b/code/app/task/crawler/wuxian/page/VideoInfoPage.php index 2446fc4..0f11924 100644 --- a/code/app/task/crawler/wuxian/page/VideoInfoPage.php +++ b/code/app/task/crawler/wuxian/page/VideoInfoPage.php @@ -67,23 +67,66 @@ class VideoInfoPage extends BasePage { if (empty($this->arrVideo)) { + // $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = $arrVideo['list'][0]; + // // print_r($arrVideo); + + // $strPlayUrl = $arrVideo['vod_play_url']; + // unset($arrVideo['vod_play_url']); + + // $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // $arrPlayUrl = explode('$', $arrPlayUrl); + // $arrPlayUrl = array_chunk($arrPlayUrl, 2); + // foreach ($arrPlayUrl as $intKey => $arrVal) { + // $strUrl = $arrVal[1] ?? ''; + // // *** 过滤掉不是 m3u8 的链接 *** + // if (!str_ends_with($strUrl, '.m3u8')) { + // continue; + // } + // $arrPlayUrl[$intKey] = [ + // 'name' => $arrVal[0], + // 'url' => $strUrl, + // ]; + // } + $arrVideo = json_decode($this->getContent(), true); - $arrVideo = $arrVideo['list'][0]; - // print_r($arrVideo); - - $strPlayUrl = $arrVideo['vod_play_url']; + $arrVideo = $arrVideo['list'][0] ?? []; + // 如果结构不正确 → 返回空数组 + if (!$arrVideo) { + return []; + } + // 2. 检查播放地址 + $strPlayUrl = $arrVideo['vod_play_url'] ?? null; + // 2. 判断是否有播放地址 + if (empty($arrVideo['vod_play_url'])) { + // 无播放地址 → 丢弃该数据 + return []; + } unset($arrVideo['vod_play_url']); - + // 替换分隔符 $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // 拆成数组 $arrPlayUrl = explode('$', $arrPlayUrl); + // 清理空值 + $arrPlayUrl = array_filter(array_map('trim', $arrPlayUrl)); + // 转成二维数组:[[name,url], [name,url], ...] $arrPlayUrl = array_chunk($arrPlayUrl, 2); - foreach ($arrPlayUrl as $intKey => $arrVal) { - $arrPlayUrl[$intKey] = [ - 'name' => $arrVal[0], - 'url' => $arrVal[1] ?? $arrVal[0], + // 最终结构 + $cleanPlayUrl = []; + foreach ($arrPlayUrl as $pair) { + $name = $pair[0] ?? ''; + $url = $pair[1] ?? ''; + // *** 过滤掉不是 m3u8 的链接 *** + if (!str_ends_with($url, '.m3u8')) { + continue; + } + $cleanPlayUrl[] = [ + 'name' => $name, + 'url' => $url, ]; } - + $arrPlayUrl = $cleanPlayUrl; + $arrVideo['vod_actor'] = trim($arrVideo['vod_actor']); $arrVideo['vod_director'] = trim($arrVideo['vod_director']); $arrVideo['vod_class'] = trim($arrVideo['vod_class']); @@ -176,15 +219,44 @@ class VideoInfoPage extends BasePage $arrExistsVideo = (array) $arrExistsVideo; + // 数据库里的旧播放源 + $oldPlayUrl = $arrExistsVideo['v_play_url'] ?? []; + + // 本次抓取的新播放源(可能不完整) + $newPagePlayUrl = $arrPageVideo['v_play_url'] ?? []; + + // 合并新老线路(新覆盖旧) + $mergedPlayUrl = array_merge($oldPlayUrl, $newPagePlayUrl); + + // 构造一个重新排序的结构 + $sortedPlayUrl = []; + + // 默认线路 + $strDefaultLine = config("video.default_line"); + + // 1. maotai 优先 + if (!empty($mergedPlayUrl[$strDefaultLine])) { + $sortedPlayUrl[$strDefaultLine] = $mergedPlayUrl[$strDefaultLine]; + } + + // 2. 其他线路顺序不变 + foreach ($mergedPlayUrl as $source => $value) { + if ($source !== $strDefaultLine) { + $sortedPlayUrl[$source] = $value; + } + } + + // 更新数据 $arrUpdate = [ 'updated_at' => new \MongoDB\BSON\UTCDateTime(), - 'v_play_url.wuxian' => $arrPageVideo['v_play_url']['wuxian'], + 'v_play_url' => $sortedPlayUrl, ]; $this->getVideoModel()->updateOne( ['v_name' => $arrPageVideo['v_name']], - ['$set' => $arrUpdate], + ['$set' => $arrUpdate] ); + $this->strPicLocalPath = $arrExistsVideo['v_pic']; } else { diff --git a/code/app/task/crawler/youzhi/page/VideoInfoPage.php b/code/app/task/crawler/youzhi/page/VideoInfoPage.php index 4416f88..69d11f1 100644 --- a/code/app/task/crawler/youzhi/page/VideoInfoPage.php +++ b/code/app/task/crawler/youzhi/page/VideoInfoPage.php @@ -67,23 +67,65 @@ class VideoInfoPage extends BasePage { if (empty($this->arrVideo)) { + // $arrVideo = json_decode($this->getContent(), true); + // $arrVideo = $arrVideo['list'][0]; + + // // print_r($arrVideo); + + // $strPlayUrl = $arrVideo['vod_play_url']; + // unset($arrVideo['vod_play_url']); + + // $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // $arrPlayUrl = explode('$', $arrPlayUrl); + // $arrPlayUrl = array_chunk($arrPlayUrl, 2); + // foreach ($arrPlayUrl as $intKey => $arrVal) { + // $strUrl = $arrVal[1] ?? ''; + // // *** 过滤掉不是 m3u8 的链接 *** + // if (!str_ends_with($strUrl, '.m3u8')) { + // continue; + // } + // $arrPlayUrl[$intKey] = [ + // 'name' => $arrVal[0], + // 'url' => $strUrl, + // ]; + // } $arrVideo = json_decode($this->getContent(), true); - $arrVideo = $arrVideo['list'][0]; - - // print_r($arrVideo); - - $strPlayUrl = $arrVideo['vod_play_url']; + $arrVideo = $arrVideo['list'][0] ?? []; + // 如果结构不正确 → 返回空数组 + if (!$arrVideo) { + return []; + } + // 2. 检查播放地址 + $strPlayUrl = $arrVideo['vod_play_url'] ?? null; + // 2. 判断是否有播放地址 + if (empty($arrVideo['vod_play_url'])) { + // 无播放地址 → 丢弃该数据 + return []; + } unset($arrVideo['vod_play_url']); - + // 替换分隔符 $arrPlayUrl = str_replace('#', '$', $strPlayUrl); + // 拆成数组 $arrPlayUrl = explode('$', $arrPlayUrl); + // 清理空值 + $arrPlayUrl = array_filter(array_map('trim', $arrPlayUrl)); + // 转成二维数组:[[name,url], [name,url], ...] $arrPlayUrl = array_chunk($arrPlayUrl, 2); - foreach ($arrPlayUrl as $intKey => $arrVal) { - $arrPlayUrl[$intKey] = [ - 'name' => $arrVal[0], - 'url' => $arrVal[1] ?? $arrVal[0], + // 最终结构 + $cleanPlayUrl = []; + foreach ($arrPlayUrl as $pair) { + $name = $pair[0] ?? ''; + $url = $pair[1] ?? ''; + // *** 过滤掉不是 m3u8 的链接 *** + if (!str_ends_with($url, '.m3u8')) { + continue; + } + $cleanPlayUrl[] = [ + 'name' => $name, + 'url' => $url, ]; } + $arrPlayUrl = $cleanPlayUrl; $arrVideo['type_id_1'] = VideoCategory::$arrParent[$arrVideo['type_id']]; @@ -174,15 +216,44 @@ class VideoInfoPage extends BasePage $arrExistsVideo = (array) $arrExistsVideo; + // 数据库里的旧播放源 + $oldPlayUrl = $arrExistsVideo['v_play_url'] ?? []; + + // 本次抓取的新播放源(可能不完整) + $newPagePlayUrl = $arrPageVideo['v_play_url'] ?? []; + + // 合并新老线路(新覆盖旧) + $mergedPlayUrl = array_merge($oldPlayUrl, $newPagePlayUrl); + + // 构造一个重新排序的结构 + $sortedPlayUrl = []; + + // 默认线路 + $strDefaultLine = config("video.default_line"); + + // 1. maotai 优先 + if (!empty($mergedPlayUrl[$strDefaultLine])) { + $sortedPlayUrl[$strDefaultLine] = $mergedPlayUrl[$strDefaultLine]; + } + + // 2. 其他线路顺序不变 + foreach ($mergedPlayUrl as $source => $value) { + if ($source !== $strDefaultLine) { + $sortedPlayUrl[$source] = $value; + } + } + + // 更新数据 $arrUpdate = [ 'updated_at' => new \MongoDB\BSON\UTCDateTime(), - 'v_play_url.youzhi' => $arrPageVideo['v_play_url']['youzhi'], + 'v_play_url' => $sortedPlayUrl, ]; $this->getVideoModel()->updateOne( ['v_name' => $arrPageVideo['v_name']], - ['$set' => $arrUpdate], + ['$set' => $arrUpdate] ); + $this->strPicLocalPath = $arrExistsVideo['v_pic']; } else { diff --git a/code/config/video.php b/code/config/video.php new file mode 100644 index 0000000..96c8a2c --- /dev/null +++ b/code/config/video.php @@ -0,0 +1,11 @@ + env('DEFAULT_LINE', 'douban'), + + // 是否测试任务 + 'task_test' => env('TASK_TEST', false), + +]; diff --git a/code/public/public/video/common.js b/code/public/public/video/common.js index 7acf7fb..653b599 100644 --- a/code/public/public/video/common.js +++ b/code/public/public/video/common.js @@ -1,4 +1,3 @@ -// import { storageObj } from '../huiyuan/public/localstorage.js'; // 无限的 debugger 兼容性好 // setInterval(function () { // debuggerCheck(); @@ -503,15 +502,15 @@ function initDPlayer(strPlayUrl) { } function findFirstUrl(obj) { - // 优先取 douban - if (Array.isArray(obj?.douban) && obj.douban.length > 0 && obj.douban[0].url) { - return obj.douban[0].url; - } - + // 优先取 默认 + // if (Array.isArray(obj?.douban) && obj.douban.length > 0 && obj.douban[0].url) { + // return obj.douban[0].url; + // } // 如果没有 douban,尝试取对象中第一个数组的第一个 url for (const key in obj) { if (Array.isArray(obj[key]) && obj[key].length > 0 && obj[key][0].url) { - return obj[key][0].url; + return obj[key]; + // return obj[key][0].url; } } @@ -575,9 +574,9 @@ document.addEventListener("DOMContentLoaded", function () { if (typeof strVideoId !== "undefined") { - if (typeof arrPlayUrl !== "undefined" && arrPlayUrl) { - arrPlayUrl = reorderObj(arrPlayUrl); - } + // if (typeof arrPlayUrl !== "undefined" && arrPlayUrl) { + // arrPlayUrl = reorderObj(arrPlayUrl); + // } // 使用示例 const statsData = { @@ -587,24 +586,57 @@ document.addEventListener("DOMContentLoaded", function () { // 调用方法1 reportStats(statsData); + // if (typeof strPlayType !== "undefined" && boolIsPlayPage) { + // if (strPlayType == 'default') { + // strPlayUrl = findFirstUrl(arrPlayUrl) + // checkLine('douban'); + // } else { + // var ActivePlayUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1] + // strPlayUrl = ActivePlayUrl.url + // checkLine(strPlayType); + // } + // initDPlayer(strPlayUrl) + // }else if(strPlayType == "default" && !boolIsPlayPage){ + // checkLine('douban'); + // } if (typeof strPlayType !== "undefined" && boolIsPlayPage) { - if (strPlayType == 'default') { - strPlayUrl = findFirstUrl(arrPlayUrl) - checkLine('douban'); - } else { - var ActivePlayUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1] - strPlayUrl = ActivePlayUrl.url + + // 用户指定线路 + if (strPlayType !== "default") { + const activeUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1]; + strPlayUrl = activeUrl.url; checkLine(strPlayType); + + // 默认播放第一个线路的第一个 URL + } else { + const defaultLine = getDefaultLine(); + strPlayUrl = getFirstPlayUrl(defaultLine); + checkLine(defaultLine); } - initDPlayer(strPlayUrl) - }else if(strPlayType == "default" && !boolIsPlayPage){ - checkLine('douban'); + + initDPlayer(strPlayUrl); + + } else if (strPlayType == "default" && !boolIsPlayPage) { + + const defaultLine = getDefaultLine(); + checkLine(defaultLine); } addHistoryFun(); } + // 获取第一个线路 key + function getDefaultLine() { + return Object.keys(arrPlayUrl)[0]; // 后端已经排序,第一位永远是默认线路 + } + + // 获取某个线路的第一个 url + function getFirstPlayUrl(playLine) { + return arrPlayUrl[playLine][0].url; + } + + }) diff --git a/doc/mongodb.md b/doc/mongodb.md index 62fba7b..4d7eda6 100644 --- a/doc/mongodb.md +++ b/doc/mongodb.md @@ -48,6 +48,27 @@ db.video.find( { "v_play_url.douban": { $exists: true } } ).limit(10) +db.video.find( + { "v_play_url.maotai": { $exists: true } } +).limit(10) + +db.video.find( + { + "v_play_url.douban": { $exists: true }, + "v_play_url.maotai": { $exists: true } + } +).limit(10) + +db.video.find({ + "v_play_url.maotai": { $exists: true }, + $expr: { + $gt: [ + { $size: { $objectToArray: "$v_play_url" } }, + 1 + ] + } +}) + // 删除某个资源线路的数据 db.video.updateMany( {},