baidu tuison

This commit is contained in:
make
2026-01-19 21:58:00 +08:00
parent 0323018c8c
commit 934ead3e11
10 changed files with 1075 additions and 466 deletions

View File

@@ -77,6 +77,7 @@ class Site extends BaseController
'd_img_logo' => $arrRows[11],
'd_content_encode' => $arrRows[12],
'info_id' => $arrRows[13],
//'d_baidu_token' => $arrRows[14],
];
$TCfgTemplate = TemplatesModel::where('t_id', $arrDomain['t_id'])->find()->t_cfg_template;
@@ -180,6 +181,7 @@ class Site extends BaseController
"d_content_encode" => $Request->post('d_content_encode'),
"t_cfg" => $Request->post('t_cfg'),
"info_id" => $Request->post('info_id'),
"d_baidu_token" => $Request->post('d_baidu_token'),
];
$arrRule = [

View File

@@ -128,7 +128,7 @@ class VideoCategoryModel extends MongoModel
"children" => []
],
[
'pinyin' => 'han-ju',
'v_category_en' => 'han-ju',
'name' => '韩剧',
"children" => []
],

View File

@@ -21,6 +21,8 @@ class CrawlerConfig
'斯诺克',
'足球',
'篮球',
'网球',
'LPL',
];
}

View File

@@ -0,0 +1,174 @@
<?php
declare(strict_types=1);
namespace app\task\logic;
use app\model\DomainModel;
class BaiduPushVideoUrlLogic
{
/**
* SiteMap 根目录
* @var string
*/
protected string $strSiteMapPath;
/**
* @var DomainModel[]
*/
protected array $arrDomainModel = [];
/**
* 每次推送条数
*/
protected int $limit = 10;
public function __construct()
{
$this->strSiteMapPath = root_path('storage/SiteMap');
}
/**
* 获取域名
*/
public function getDomain(): array
{
if (empty($this->arrDomainModel)) {
$this->arrDomainModel = DomainModel::getAllDomainOnCache();
}
return $this->arrDomainModel;
}
/**
* 推送百度 URL任务入口
*/
public function pushBaiduUrl(): void
{
foreach ($this->getDomain() as $DomainModel) {
$domain = $DomainModel->d_domain;
$strBaiduToken = $DomainModel->d_baidu_token ?? "";
$domainDir = $this->strSiteMapPath . DIRECTORY_SEPARATOR . $domain;
if (!is_dir($domainDir)) {
continue;
}
$this->pushDomainUrls($domain, $strBaiduToken, $domainDir);
}
}
/**
* 推送单个域名
*/
protected function pushDomainUrls(string $domain, string $strBaiduToken, string $domainDir): void
{
$stateFile = $domainDir . '/baidu_state.json';
if(empty($strBaiduToken)){
return ;
}
$strApi = 'http://data.zz.baidu.com/urls?site=https://' . $domain . '&token=' . $strBaiduToken;
// $strApi = 'http://data.zz.baidu.com/urls?site=https://www.aaggc.com&token=B4bzeDDBHhnoBnov';
// 1⃣ 读取 txt 文件
$txtFiles = glob($domainDir . '/*.txt');
sort($txtFiles);
if (empty($txtFiles)) {
return;
}
// 2⃣ 读取进度
if (file_exists($stateFile)) {
$state = json_decode(file_get_contents($stateFile), true);
} else {
$state = [
'file_index' => 0,
'line_index' => 0,
];
}
$fileIndex = (int)$state['file_index'];
$lineIndex = (int)$state['line_index'];
$arrPushUrls = [];
$newFileIndex = $fileIndex;
$newLineIndex = $lineIndex;
// 3⃣ 按顺序取 URL
for ($i = $fileIndex; $i < count($txtFiles); $i++) {
$lines = file($txtFiles[$i], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$start = ($i === $fileIndex) ? $lineIndex : 0;
for ($j = $start; $j < count($lines); $j++) {
$url = trim($lines[$j]);
if ($url === '') {
continue;
}
$arrPushUrls[] = $url;
$newFileIndex = $i;
$newLineIndex = $j + 1;
if (count($arrPushUrls) >= $this->limit) {
break 2;
}
}
// 当前文件读完
$newFileIndex = $i + 1;
$newLineIndex = 0;
}
// 4⃣ 没有可推送 URL
if (empty($arrPushUrls)) {
return;
}
// 5⃣ curl 推送
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $strApi,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => implode("\n", $arrPushUrls),
CURLOPT_HTTPHEADER => [
'Content-Type: text/plain; charset=utf-8'
],
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
]);
$result = curl_exec($ch);
if ($result === false) {
curl_close($ch);
return;
}
curl_close($ch);
// 6⃣ 解析结果
$data = json_decode($result, true);
// 7⃣ 成功才更新进度
if (isset($data['success']) && $data['success'] > 0) {
file_put_contents(
$stateFile,
json_encode([
'file_index' => $newFileIndex,
'line_index' => $newLineIndex,
'updated_at' => date('Y-m-d H:i:s'),
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
);
}
}
}

View File

@@ -132,24 +132,6 @@ class VideoSiteMapLogic
*
* @return void
*/
// public function generateSiteMap()
// {
// $arrResult = $this->VideoModel->findPaginatedWithCache([], 1, 1);
// $this->intTotal = $arrResult['total'];
// $this->generateMapIndex();
// $this->generateMapMain();
// $intTotalPage = ceil($this->intTotal / $this->intPageSize);
// for ($intPage = 1; $intPage <= $intTotalPage; $intPage++) {
// $this->generateMapInfo($intPage);
// }
// echo date('Y-m-d H:i:s') . PHP_EOL;
// }
protected function generateMapInfo(int $intPage)
{
$intStartPage = $intPage;
@@ -208,6 +190,7 @@ EOF;
$arrArgs = [
'intVId' => $Video->v_id,
'strPinYin' => $Video->v_name_en,
'strPinyin' => $Video->v_name_en,
];
if ($arrUrlFamily && !empty($arrUrlFamily)) {
@@ -283,6 +266,10 @@ EOF;
foreach ($this->getDomain() as $DomainModel) {
// 用于 sitemap + txt 的 URL 去重池
$arrUrlPool = [];
$strDomainDir = $this->strSiteMapPath . $DomainModel->d_domain;
if (is_dir($strDomainDir) == false) {
mkdir($strDomainDir);
@@ -316,7 +303,15 @@ EOF;
<priority>0.8</priority>
</url>
EOF;
file_put_contents($strMapIndexFile, $strContent);
//file_put_contents($strMapIndexFile, $strContent);
$arrUrlPool["https://www.{$DomainModel->d_domain}/"] = [
'lastmod' => $this->strDate,
'changefreq' => 'daily',
'priority' => '1.0',
];
// 分类首页 '/vodtype/{strParentCategory}',
foreach ($this->arrVideoCategory as $strParentCategoryKey => $arrParentCategory) {
@@ -348,10 +343,14 @@ EOF;
<priority>0.8</priority>
</url>
EOF;
file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
//file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
$arrUrlPool[$strUrl] = [
'lastmod' => $this->strDate,
'changefreq' => 'weekly',
'priority' => '0.8',
];
}
// 分类列表 '/vodtype-{strParentCategory}/{strCategory}-{strYear}-{strArea}-{strOrder}/{strLang}-page{intPage}',
foreach ($this->arrVideoCategory as $arrParentCategory) {
foreach ($arrParentCategory['children'] as $arrChildrenCategory) {
@@ -391,7 +390,12 @@ EOF;
<priority>0.8</priority>
</url>
EOF;
file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
//file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
$arrUrlPool[$strUrl] = [
'lastmod' => $this->strDate,
'changefreq' => 'weekly',
'priority' => '0.8',
];
// }
// }
// }
@@ -432,7 +436,12 @@ EOF;
<priority>0.8</priority>
</url>
EOF;
file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
//file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
$arrUrlPool[$strUrl] = [
'lastmod' => $this->strDate,
'changefreq' => 'weekly',
'priority' => '0.8',
];
}
}
}
@@ -442,7 +451,38 @@ EOF;
$strContent = <<<EOF
</urlset>
EOF;
file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
//file_put_contents($strMapIndexFile, $strContent, FILE_APPEND);
$strXml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
XML;
foreach ($arrUrlPool as $url => $meta) {
$strXml .= <<<XML
<url>
<loc>{$url}</loc>
<lastmod>{$meta['lastmod']}</lastmod>
<changefreq>{$meta['changefreq']}</changefreq>
<priority>{$meta['priority']}</priority>
</url>
XML;
}
$strXml .= "\n</urlset>";
file_put_contents($strMapIndexFile, $strXml);
$strTxtFile = $strDomainDir . '/sitemap-main.txt';
$strTxt = implode("\n", array_keys($arrUrlPool));
file_put_contents($strTxtFile, $strTxt);
}
}

View File

@@ -7,6 +7,7 @@ namespace app\task\module;
use app\model\PlanTaskModel;
use app\task\logic\SiteMapLogic;
use app\task\logic\VideoSiteMapLogic;
use app\task\logic\BaiduPushVideoUrlLogic;
use microserver\QueueManage;
use microserver\ProcessSanitizer;
@@ -90,6 +91,11 @@ class PlanTask
case 'GENERATE_VIDEO_SEO_WORDS':
self::generateVideoSEOWords();
break;
case 'PUSH_BAIDU_VIDEO_URL':
self::pushBaiduVideoUrl();
break;
}
}
}
@@ -303,6 +309,22 @@ class PlanTask
$QueueManage->set($arrTask);
}
/**
* Undocumented function
*
* @return void
*/
public static function pushBaiduVideoUrl()
{
$arrTask = [
'callback' => [BaiduPushVideoUrlLogic::class, 'pushBaiduUrl'],
'data' => []
];
$QueueManage = new QueueManage(2);
$QueueManage->set($arrTask);
}
/**
* Undocumented function
*

View File

@@ -0,0 +1,27 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class AddBaiduTokenToVideoTable extends Migrator
{
public function up()
{
$table = $this->table('domain');
$table
->addColumn(
Column::string('d_baidu_token', 255)
->setNullable(true)
->setComment('百度推送token')
)
->update();
}
public function down()
{
$table = $this->table('domain');
$table
->removeColumn('d_baidu_token')
->update();
}
}

View File

@@ -110,12 +110,22 @@ class PlanTaskSeeder
'pt_code' => 'PULL_DOU_BAN_SHI_PIN',
'pt_enable' => 0,
'pt_limit' => 1 * 24 * 3600,
], [
],
[
'pt_name' => '茅台资源库全量采集',
'pt_code' => 'PULL_MAO_TAI_SHI_PIN',
'pt_enable' => 0,
'pt_limit' => 1 * 24 * 3600,
],
[
'pt_name' => '推送视频url到百度收录',
'pt_code' => 'PUSH_BAIDU_VIDEO_URL',
'pt_enable' => 0,
'pt_limit' => 1 * 24 * 3600,
],
];

View File

@@ -1,195 +1,117 @@
<?php
/**
* GPT 新模板 URL Family PoolA 方案)
* - prefixIndex × templateIndex 生成
* - 每套都有 idA001…
* - 每个页面1 pattern + 1 route
* - 每套都有稳定 idA001…
* - 文件被 require 时,直接返回 array
* - task / CLI / Web 全安全
*/
function buildUrlFamilyPool(): array
{
/** 页面定义(你给的) */
// =====================
// 1⃣ 页面定义
// =====================
$pages = [
'play' => [
'sort' => 1,
'prefix' => [
'video', // 主
'play', // 主
'vodplay', // 历史
'watch', // 英文
'kan', // 拼音(看)
'player', // 英文
'bofang', // 英文
'm3u8', // 英文
'bf', // 英文
'video','play','vodplay','watch','kan','player','bofang','m3u8','bf',
],
'type' => 'play'
'type' => 'play',
],
'detail_forge' => [
'sort' => 2,
'prefix' => [
'video', // 主
'detail', // 主
'info', // 主
'vod', // 行业通用
'movie', // 英文
'film', // 英文
'xiangqing',
'shipin',
'neirong',
'dianying',
'video','detail','info','vod','movie','film',
'xiangqing','shipin','neirong','dianying',
],
'type' => 'detail_forge'
'type' => 'detail_forge',
],
'detail' => [
'sort' => 3,
'prefix' => [
'video', // 主
'detail', // 主
'info', // 主
'vod', // 行业通用
'movie', // 英文
'film', // 英文
'xiangqing',
'shipin',
'neirong',
'dianying',
'video','detail','info','vod','movie','film',
'xiangqing','shipin','neirong','dianying',
],
'type' => 'detail'
'type' => 'detail',
],
'category_child' => [
'sort' => 4,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
'fenlei','category','class','type','genres','leixing','videotype',
],
'type' => 'category_child'
'type' => 'category_child',
],
'category_parent' => [
'sort' => 5,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
'fenlei','category','class','type','genres','leixing','videotype',
],
'type' => 'category_parent'
'type' => 'category_parent',
],
'rank_list' => [
'sort' => 6,
'prefix' => [
'top', // 主
'rank', // 主
'paihangban', // 拼音
'ranking', // 英文
'hot', // 热门(谨慎)
'phb',
'top','rank','paihangban','ranking','hot','phb',
],
'type' => 'rank_list'
'type' => 'rank_list',
],
'category_home' => [
'sort' => 7,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
'fenlei','category','class','type','genres','leixing','videotype',
],
'type' => 'category_home'
'type' => 'category_home',
],
'rank_index' => [
'sort' => 8,
'prefix' => [
'top', // 主
'rank', // 主
'paihangban', // 拼音
'ranking', // 英文
'hot', // 热门(谨慎)
'phb',
'top','rank','paihangban','ranking','hot','phb',
],
'type' => 'rank_index'
'type' => 'rank_index',
],
'search' => [
'sort' => 9,
'prefix' => [
'search', // 主
'query', // 主
'sou', // 拼音
'find', // 英文
'get'
'search','query','sou','find','get',
],
'type' => 'search'
'type' => 'search',
],
'history' => [
'sort' => 10,
'prefix' => [
'history', // 主
'his', // 简写
'jilu', // 拼音
'record', // 英文
'history','his','jilu','record',
],
'type' => 'history'
'type' => 'history',
],
];
/** 每个 type 的 8 套模板(你已测试可用) */
// =====================
// 2⃣ 模板定义(每类 8 套)
// =====================
$templates = [
'category_home' => [
'pattern' => [
'{prefix}',
'{prefix}/index',
'{prefix}/home',
'{prefix}/p',
'{prefix}/1',
'{prefix}-1',
'{prefix}-index',
'{prefix}-home',
'{prefix}','{prefix}/index','{prefix}/home','{prefix}/p',
'{prefix}/1','{prefix}-1','{prefix}-index','{prefix}-home',
],
'routes' => [
'/{prefix}',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/p',
'/{prefix}/1',
'/{prefix}/-1',
'/{prefix}-index',
'/{prefix}-home',
'/{prefix}','/{prefix}/index','/{prefix}/home','/{prefix}/p',
'/{prefix}/1','/{prefix}-1','/{prefix}-index','/{prefix}-home',
],
],
'category_parent' => [
'pattern' => [
'{prefix}/{strParentCategory}',
'{prefix}/{strParentCategory}/index',
'{prefix}/{strParentCategory}/home',
'{prefix}/p/{strParentCategory}',
'{prefix}/1/{strParentCategory}',
'{prefix}/1-{strParentCategory}',
'{prefix}/{strParentCategory}/1',
'{prefix}/{strParentCategory}-1',
'{prefix}/{strParentCategory}','{prefix}/{strParentCategory}/index',
'{prefix}/{strParentCategory}/home','{prefix}/p/{strParentCategory}',
'{prefix}/1/{strParentCategory}','{prefix}/1-{strParentCategory}',
'{prefix}/{strParentCategory}/1','{prefix}/{strParentCategory}-1',
],
'routes' => [
'/{prefix}/:strParentCategory',
'/{prefix}/:strParentCategory/index',
'/{prefix}/:strParentCategory/home',
'/{prefix}/p/:strParentCategory',
'/{prefix}/1/:strParentCategory',
'/{prefix}/1-:strParentCategory',
'/{prefix}/:strParentCategory/1',
'/{prefix}/:strParentCategory-1',
'/{prefix}/:strParentCategory','/{prefix}/:strParentCategory/index',
'/{prefix}/:strParentCategory/home','/{prefix}/p/:strParentCategory',
'/{prefix}/1/:strParentCategory','/{prefix}/1-:strParentCategory',
'/{prefix}/:strParentCategory/1','/{prefix}/:strParentCategory-1',
],
],
@@ -218,70 +140,42 @@ function buildUrlFamilyPool(): array
'rank_index' => [
'pattern' => [
'{prefix}',
'{prefix}/index',
'{prefix}/all',
'{prefix}/home',
'{prefix}/1',
'{prefix}-index',
'{prefix}-all',
'{prefix}-home',
'{prefix}','{prefix}/index','{prefix}/all','{prefix}/home',
'{prefix}/1','{prefix}-index','{prefix}-all','{prefix}-home',
],
'routes' => [
'/{prefix}',
'/{prefix}/index',
'/{prefix}/all',
'/{prefix}/home',
'/{prefix}/1',
'/{prefix}-index',
'/{prefix}-all',
'/{prefix}-home',
'/{prefix}','/{prefix}/index','/{prefix}/all','/{prefix}/home',
'/{prefix}/1','/{prefix}-index','/{prefix}-all','/{prefix}-home',
],
],
'rank_list' => [
'pattern' => [
'{prefix}/{strSortType}',
'{prefix}/{strSortType}/index',
'{prefix}/{strSortType}/home',
'{prefix}/{strSortType}/1',
'{prefix}/{strSortType}-1',
'{prefix}-{strSortType}',
'{prefix}-{strSortType}/index',
'{prefix}-{strSortType}/1',
'{prefix}/{strSortType}','{prefix}/{strSortType}/index',
'{prefix}/{strSortType}/home','{prefix}/{strSortType}/1',
'{prefix}/{strSortType}-1','{prefix}-{strSortType}',
'{prefix}-{strSortType}/index','{prefix}-{strSortType}/1',
],
'routes' => [
'/{prefix}/:strSortType',
'/{prefix}/:strSortType/index',
'/{prefix}/:strSortType/home',
'/{prefix}/:strSortType/1',
'/{prefix}/:strSortType-1',
'/{prefix}-:strSortType',
'/{prefix}-:strSortType/index',
'/{prefix}-:strSortType/1',
'/{prefix}/:strSortType','/{prefix}/:strSortType/index',
'/{prefix}/:strSortType/home','/{prefix}/:strSortType/1',
'/{prefix}/:strSortType-1','/{prefix}-:strSortType',
'/{prefix}-:strSortType/index','/{prefix}-:strSortType/1',
],
],
'detail' => [
'pattern' => [
'{prefix}/{strPinyin}-{intVId}',
'{prefix}/{intVId}-{strPinyin}',
'{prefix}/{strPinyin}/{intVId}',
'{prefix}/{intVId}',
'{prefix}-{strPinyin}-{intVId}',
'{prefix}-{intVId}-{strPinyin}',
'{prefix}/id-{intVId}',
'{prefix}/pinyin-{strPinyin}',
'{prefix}/{strPinyin}-{intVId}','{prefix}/{intVId}-{strPinyin}',
'{prefix}/{strPinyin}/{intVId}','{prefix}/{intVId}',
'{prefix}-{strPinyin}-{intVId}','{prefix}-{intVId}-{strPinyin}',
'{prefix}/id-{intVId}','{prefix}/pinyin-{strPinyin}',
],
'routes' => [
'/{prefix}/:strPinyin-:intVId',
'/{prefix}/:intVId-:strPinyin',
'/{prefix}/:strPinyin/:intVId',
'/{prefix}/:intVId',
'/{prefix}-:strPinyin-:intVId',
'/{prefix}-:intVId-:strPinyin',
'/{prefix}/id-:intVId',
'/{prefix}/pinyin-:strPinyin',
'/{prefix}/:strPinyin-:intVId','/{prefix}/:intVId-:strPinyin',
'/{prefix}/:strPinyin/:intVId','/{prefix}/:intVId',
'/{prefix}-:strPinyin-:intVId','/{prefix}-:intVId-:strPinyin',
'/{prefix}/id-:intVId','/{prefix}/pinyin-:strPinyin',
],
],
@@ -333,57 +227,36 @@ function buildUrlFamilyPool(): array
'search' => [
'pattern' => [
'{prefix}',
'{prefix}.html',
'{prefix}/index',
'{prefix}/home',
'{prefix}/keywords',
'{prefix}-index',
'{prefix}-home',
'{prefix}-keywords',
'{prefix}','{prefix}.html','{prefix}/index','{prefix}/home',
'{prefix}/keywords','{prefix}-index','{prefix}-home','{prefix}-keywords',
],
'routes' => [
'/{prefix}',
'/{prefix}.html',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/keywords',
'/{prefix}-index',
'/{prefix}-home',
'/{prefix}-keywords',
'/{prefix}','/{prefix}.html','/{prefix}/index','/{prefix}/home',
'/{prefix}/keywords','/{prefix}-index','/{prefix}-home','/{prefix}-keywords',
],
],
'history' => [
'pattern' => [
'{prefix}',
'{prefix}.html',
'{prefix}/index',
'{prefix}/home',
'{prefix}/keywords',
'{prefix}-index',
'{prefix}-home',
'{prefix}-keywords',
'{prefix}','{prefix}.html','{prefix}/index','{prefix}/home',
'{prefix}/keywords','{prefix}-index','{prefix}-home','{prefix}-keywords',
],
'routes' => [
'/{prefix}',
'/{prefix}.html',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/keywords',
'/{prefix}-index',
'/{prefix}-home',
'/{prefix}-keywords',
'/{prefix}','/{prefix}.html','/{prefix}/index','/{prefix}/home',
'/{prefix}/keywords','/{prefix}-index','/{prefix}-home','/{prefix}-keywords',
],
],
];
// 🔴【新增 1】加载 index落盘 ID
// =====================
// 3⃣ ID 索引(落盘
// =====================
$indexFile = __DIR__ . '/url_family_index.php';
$index = file_exists($indexFile) ? require $indexFile : [];
// 🔴【新增 2】计算当前最大 A 编号
// =====================
// 4⃣ 计算当前最大 A 编号
// =====================
$maxId = 0;
foreach ($index as $aid) {
$num = (int)substr($aid, 1);
@@ -392,33 +265,24 @@ function buildUrlFamilyPool(): array
}
}
// 页面按 sort 排序(保证路由注册顺序)
// =====================
// 5⃣ 构造 families
// =====================
uasort($pages, fn($a, $b) => $a['sort'] <=> $b['sort']);
// prefix 套数
$prefixSuiteCount = max(array_map(fn($p) => count($p['prefix']), $pages));
$families = [];
// ❌【删除】$seq = 1;
for ($pi = 0; $pi < $prefixSuiteCount; $pi++) {
for ($ti = 0; $ti < 8; $ti++) {
/**
* 🔴【新增 3】构造 family 唯一指纹 key
* 只要 page / prefix / 模板索引一样URL 身份就一样
*/
$familyKeyParts = [];
foreach ($pages as $pageKey => $page) {
$prefix = $page['prefix'][$pi] ?? end($page['prefix']);
$familyKeyParts[] = $pageKey . ':' . $prefix;
}
$familyKey = implode('|', $familyKeyParts) . '|tpl' . $ti;
// 🔴【新增 4】从 index 取 A 编号(没有就新增)
if (!isset($index[$familyKey])) {
$maxId++;
$index[$familyKey] = 'A' . str_pad((string)$maxId, 3, '0', STR_PAD_LEFT);
@@ -426,14 +290,11 @@ function buildUrlFamilyPool(): array
$aid = $index[$familyKey];
// 🔴【修改】family 的 id 不再用 $seq
$family = [
'id' => $aid,
'home' => [
'pattern' => '',
'routes' => [
'/'
]
'routes' => ['/'],
],
];
@@ -444,7 +305,6 @@ function buildUrlFamilyPool(): array
}
$prefix = $page['prefix'][$pi] ?? end($page['prefix']);
$pattern = str_replace('{prefix}', $prefix, $templates[$type]['pattern'][$ti]);
$route = str_replace('{prefix}', $prefix, $templates[$type]['routes'][$ti]);
@@ -455,22 +315,18 @@ function buildUrlFamilyPool(): array
];
}
// 🔴【修改】用 A 编号做 key避免被重排
$families[$aid] = $family;
}
}
// 🔴【新增 5】index 落盘(只会 append
// =====================
// 6⃣ index 落盘 + 排序返回
// =====================
file_put_contents(
$indexFile,
"<?php\nreturn " . var_export($index, true) . ";\n"
);
// 🔴【新增 6】按 A 编号排序,输出稳定顺序
ksort($families);
return array_values($families);
}
return buildUrlFamilyPool();

View File

@@ -0,0 +1,476 @@
<?php
/**
* GPT 新模板 URL Family PoolA 方案)
* - prefixIndex × templateIndex 生成
* - 每套都有 idA001…
* - 每个页面1 pattern + 1 route
*/
function buildUrlFamilyPool(): array
{
/** 页面定义(你给的) */
$pages = [
'play' => [
'sort' => 1,
'prefix' => [
'video', // 主
'play', // 主
'vodplay', // 历史
'watch', // 英文
'kan', // 拼音(看)
'player', // 英文
'bofang', // 英文
'm3u8', // 英文
'bf', // 英文
],
'type' => 'play'
],
'detail_forge' => [
'sort' => 2,
'prefix' => [
'video', // 主
'detail', // 主
'info', // 主
'vod', // 行业通用
'movie', // 英文
'film', // 英文
'xiangqing',
'shipin',
'neirong',
'dianying',
],
'type' => 'detail_forge'
],
'detail' => [
'sort' => 3,
'prefix' => [
'video', // 主
'detail', // 主
'info', // 主
'vod', // 行业通用
'movie', // 英文
'film', // 英文
'xiangqing',
'shipin',
'neirong',
'dianying',
],
'type' => 'detail'
],
'category_child' => [
'sort' => 4,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
],
'type' => 'category_child'
],
'category_parent' => [
'sort' => 5,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
],
'type' => 'category_parent'
],
'rank_list' => [
'sort' => 6,
'prefix' => [
'top', // 主
'rank', // 主
'paihangban', // 拼音
'ranking', // 英文
'hot', // 热门(谨慎)
'phb',
],
'type' => 'rank_list'
],
'category_home' => [
'sort' => 7,
'prefix' => [
'fenlei', // 主
'category', // 英文
'class', // 主
'type', // 主
'genres', // 英文(类型)
'leixing', // 拼音
'videotype', // 拼音
],
'type' => 'category_home'
],
'rank_index' => [
'sort' => 8,
'prefix' => [
'top', // 主
'rank', // 主
'paihangban', // 拼音
'ranking', // 英文
'hot', // 热门(谨慎)
'phb',
],
'type' => 'rank_index'
],
'search' => [
'sort' => 9,
'prefix' => [
'search', // 主
'query', // 主
'sou', // 拼音
'find', // 英文
'get'
],
'type' => 'search'
],
'history' => [
'sort' => 10,
'prefix' => [
'history', // 主
'his', // 简写
'jilu', // 拼音
'record', // 英文
],
'type' => 'history'
],
];
/** 每个 type 的 8 套模板(你已测试可用) */
$templates = [
'category_home' => [
'pattern' => [
'{prefix}',
'{prefix}/index',
'{prefix}/home',
'{prefix}/p',
'{prefix}/1',
'{prefix}-1',
'{prefix}-index',
'{prefix}-home',
],
'routes' => [
'/{prefix}',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/p',
'/{prefix}/1',
'/{prefix}/-1',
'/{prefix}-index',
'/{prefix}-home',
],
],
'category_parent' => [
'pattern' => [
'{prefix}/{strParentCategory}',
'{prefix}/{strParentCategory}/index',
'{prefix}/{strParentCategory}/home',
'{prefix}/p/{strParentCategory}',
'{prefix}/1/{strParentCategory}',
'{prefix}/1-{strParentCategory}',
'{prefix}/{strParentCategory}/1',
'{prefix}/{strParentCategory}-1',
],
'routes' => [
'/{prefix}/:strParentCategory',
'/{prefix}/:strParentCategory/index',
'/{prefix}/:strParentCategory/home',
'/{prefix}/p/:strParentCategory',
'/{prefix}/1/:strParentCategory',
'/{prefix}/1-:strParentCategory',
'/{prefix}/:strParentCategory/1',
'/{prefix}/:strParentCategory-1',
],
],
'category_child' => [
'pattern' => [
'{prefix}/{strParentCategory}/{strCategory}/page{intPage}',
'{prefix}/{strParentCategory}/{strCategory}-page{intPage}',
'{prefix}-{strParentCategory}/{strCategory}/page{intPage}',
'{prefix}-{strParentCategory}/{strCategory}-page{intPage}',
'{prefix}/{strParentCategory}/{strCategory}/{intPage}',
'{prefix}/{strParentCategory}/{strCategory}-{intPage}',
'{prefix}-{strParentCategory}/{strCategory}/{intPage}',
'{prefix}-{strParentCategory}/{strCategory}-{intPage}',
],
'routes' => [
'/{prefix}/:strParentCategory/:strCategory/page:intPage',
'/{prefix}/:strParentCategory/:strCategory-page:intPage',
'/{prefix}-:strParentCategory/:strCategory/page:intPage',
'/{prefix}-:strParentCategory/:strCategory-page:intPage',
'/{prefix}/:strParentCategory/:strCategory/:intPage',
'/{prefix}/:strParentCategory/:strCategory-:intPage',
'/{prefix}-:strParentCategory/:strCategory/:intPage',
'/{prefix}-:strParentCategory/:strCategory-:intPage',
],
],
'rank_index' => [
'pattern' => [
'{prefix}',
'{prefix}/index',
'{prefix}/all',
'{prefix}/home',
'{prefix}/1',
'{prefix}-index',
'{prefix}-all',
'{prefix}-home',
],
'routes' => [
'/{prefix}',
'/{prefix}/index',
'/{prefix}/all',
'/{prefix}/home',
'/{prefix}/1',
'/{prefix}-index',
'/{prefix}-all',
'/{prefix}-home',
],
],
'rank_list' => [
'pattern' => [
'{prefix}/{strSortType}',
'{prefix}/{strSortType}/index',
'{prefix}/{strSortType}/home',
'{prefix}/{strSortType}/1',
'{prefix}/{strSortType}-1',
'{prefix}-{strSortType}',
'{prefix}-{strSortType}/index',
'{prefix}-{strSortType}/1',
],
'routes' => [
'/{prefix}/:strSortType',
'/{prefix}/:strSortType/index',
'/{prefix}/:strSortType/home',
'/{prefix}/:strSortType/1',
'/{prefix}/:strSortType-1',
'/{prefix}-:strSortType',
'/{prefix}-:strSortType/index',
'/{prefix}-:strSortType/1',
],
],
'detail' => [
'pattern' => [
'{prefix}/{strPinyin}-{intVId}',
'{prefix}/{intVId}-{strPinyin}',
'{prefix}/{strPinyin}/{intVId}',
'{prefix}/{intVId}',
'{prefix}-{strPinyin}-{intVId}',
'{prefix}-{intVId}-{strPinyin}',
'{prefix}/id-{intVId}',
'{prefix}/pinyin-{strPinyin}',
],
'routes' => [
'/{prefix}/:strPinyin-:intVId',
'/{prefix}/:intVId-:strPinyin',
'/{prefix}/:strPinyin/:intVId',
'/{prefix}/:intVId',
'/{prefix}-:strPinyin-:intVId',
'/{prefix}-:intVId-:strPinyin',
'/{prefix}/id-:intVId',
'/{prefix}/pinyin-:strPinyin',
],
],
'detail_forge' => [
'pattern' => [
'{prefix}/{strPinyin}-{intVId}-{intVForgeId}',
'{prefix}/{intVId}-{strPinyin}/{intVForgeId}',
'{prefix}/{strPinyin}/{intVId}-{intVForgeId}',
'{prefix}/{intVId}/{intVForgeId}',
'{prefix}-{strPinyin}-{intVId}/{intVForgeId}',
'{prefix}-{intVId}-{strPinyin}/{intVForgeId}',
'{prefix}/id-{intVId}-{intVForgeId}',
'{prefix}/pinyin-{strPinyin}/{intVForgeId}',
],
'routes' => [
'/{prefix}/:strPinyin-:intVId-:intVForgeId',
'/{prefix}/:intVId-:strPinyin/:intVForgeId',
'/{prefix}/:strPinyin/:intVId-:intVForgeId',
'/{prefix}/:intVId/:intVForgeId',
'/{prefix}-:strPinyin-:intVId/:intVForgeId',
'/{prefix}-:intVId-:strPinyin/:intVForgeId',
'/{prefix}/id-:intVId-:intVForgeId',
'/{prefix}/pinyin-:strPinyin/:intVForgeId',
],
],
'play' => [
'pattern' => [
'{prefix}/{strPinyin}-{intVId}-{strPlayType}-{intPlayIndex}',
'{prefix}/{strPinyin}-{intVId}/{strPlayType}-{intPlayIndex}',
'{prefix}/{intVId}-{strPlayType}-{intPlayIndex}',
'{prefix}/{intVId}/{strPlayType}-{intPlayIndex}',
'{prefix}-{strPinyin}-{intVId}-{strPlayType}-{intPlayIndex}',
'{prefix}-{intVId}-{strPinyin}/{strPlayType}-{intPlayIndex}',
'{prefix}-{intVId}-{strPlayType}-{intPlayIndex}',
'{prefix}-{intVId}/{strPlayType}-{intPlayIndex}',
],
'routes' => [
'/{prefix}/:strPinyin-:intVId-:strPlayType-:intPlayIndex',
'/{prefix}/:strPinyin-:intVId/:strPlayType-:intPlayIndex',
'/{prefix}/:intVId-:strPlayType-:intPlayIndex',
'/{prefix}/:intVId/:strPlayType-:intPlayIndex',
'/{prefix}-:strPinyin-:intVId-:strPlayType-:intPlayIndex',
'/{prefix}-:intVId-:strPinyin/:strPlayType-:intPlayIndex',
'/{prefix}-:intVId-:strPlayType-:intPlayIndex',
'/{prefix}-:intVId/:strPlayType-:intPlayIndex',
],
],
'search' => [
'pattern' => [
'{prefix}',
'{prefix}.html',
'{prefix}/index',
'{prefix}/home',
'{prefix}/keywords',
'{prefix}-index',
'{prefix}-home',
'{prefix}-keywords',
],
'routes' => [
'/{prefix}',
'/{prefix}.html',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/keywords',
'/{prefix}-index',
'/{prefix}-home',
'/{prefix}-keywords',
],
],
'history' => [
'pattern' => [
'{prefix}',
'{prefix}.html',
'{prefix}/index',
'{prefix}/home',
'{prefix}/keywords',
'{prefix}-index',
'{prefix}-home',
'{prefix}-keywords',
],
'routes' => [
'/{prefix}',
'/{prefix}.html',
'/{prefix}/index',
'/{prefix}/home',
'/{prefix}/keywords',
'/{prefix}-index',
'/{prefix}-home',
'/{prefix}-keywords',
],
],
];
// 🔴【新增 1】加载 index落盘 ID
$indexFile = __DIR__ . '/url_family_index.php';
$index = file_exists($indexFile) ? require $indexFile : [];
// 🔴【新增 2】计算当前最大 A 编号
$maxId = 0;
foreach ($index as $aid) {
$num = (int)substr($aid, 1);
if ($num > $maxId) {
$maxId = $num;
}
}
// 页面按 sort 排序(保证路由注册顺序)
uasort($pages, fn($a, $b) => $a['sort'] <=> $b['sort']);
// prefix 套数
$prefixSuiteCount = max(array_map(fn($p) => count($p['prefix']), $pages));
$families = [];
// ❌【删除】$seq = 1;
for ($pi = 0; $pi < $prefixSuiteCount; $pi++) {
for ($ti = 0; $ti < 8; $ti++) {
/**
* 🔴【新增 3】构造 family 唯一指纹 key
* 只要 page / prefix / 模板索引一样URL 身份就一样
*/
$familyKeyParts = [];
foreach ($pages as $pageKey => $page) {
$prefix = $page['prefix'][$pi] ?? end($page['prefix']);
$familyKeyParts[] = $pageKey . ':' . $prefix;
}
$familyKey = implode('|', $familyKeyParts) . '|tpl' . $ti;
// 🔴【新增 4】从 index 取 A 编号(没有就新增)
if (!isset($index[$familyKey])) {
$maxId++;
$index[$familyKey] = 'A' . str_pad((string)$maxId, 3, '0', STR_PAD_LEFT);
}
$aid = $index[$familyKey];
// 🔴【修改】family 的 id 不再用 $seq
$family = [
'id' => $aid,
'home' => [
'pattern' => '',
'routes' => [
'/'
]
],
];
foreach ($pages as $pageKey => $page) {
$type = $page['type'];
if (!isset($templates[$type])) {
continue;
}
$prefix = $page['prefix'][$pi] ?? end($page['prefix']);
$pattern = str_replace('{prefix}', $prefix, $templates[$type]['pattern'][$ti]);
$route = str_replace('{prefix}', $prefix, $templates[$type]['routes'][$ti]);
$family[$pageKey] = [
'sort' => $page['sort'],
'pattern' => $pattern,
'routes' => [$route],
];
}
// 🔴【修改】用 A 编号做 key避免被重排
$families[$aid] = $family;
}
}
// 🔴【新增 5】index 落盘(只会 append
file_put_contents(
$indexFile,
"<?php\nreturn " . var_export($index, true) . ";\n"
);
// 🔴【新增 6】按 A 编号排序,输出稳定顺序
ksort($families);
return array_values($families);
}
return buildUrlFamilyPool();