This commit is contained in:
make
2026-01-09 01:28:23 +08:00
parent eb8c097777
commit 90fc16fbc3
241 changed files with 26518 additions and 3570 deletions

View File

@@ -14,6 +14,13 @@ use app\model\NovelClicksModel;
use app\model\NovelModel;
use app\common\helper\SiteStyle;
use app\common\helper\CssBuilder;
use app\common\helper\JsBuilder;
use app\common\helper\UrlBuilder;
use app\common\seo\SeoRenderer;
use app\common\CommentPool;
use app\common\PinlunVariant;
use think\facade\Request;
use think\facade\Config;
use think\exception\HttpException;
@@ -65,6 +72,18 @@ class SiteContext
*/
public $NovelClicksModel;
/**
* TpStyle
*
*/
public $TpStyle;
/**
* UrlBuilder
*
*/
public $UrlBuilder;
public function __construct()
{
$this->Request = request();
@@ -84,6 +103,9 @@ class SiteContext
$this->DomainModel = DomainModel::getDomainOnCacheByDomain($strDomain);
$this->TpStyle = SiteStyle::getConfig();
$this->UrlBuilder = new UrlBuilder($this->TpStyle);
if (empty($this->DomainModel)) {
throw new HttpException(404, 'Site config not Found');
}
@@ -142,12 +164,20 @@ class SiteContext
View::assign("strBookShelfUrlTemp", $strBookShelfUrlTemp);
View::assign("strUserUrlTemp", $strUserUrlTemp);
} else {
// $strPcUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_PC_PATH_URL', '', false);
$strRankUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_RANK_INDEX_URL', '', false);
$strSearchListUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_SEARCH_LIST_URL', '', false);
$strHistoryUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_HISTORY_LIST_URL', '', false);
$strYouQingLiangJieTemp = $this->DomainModel->getFomartSubject('YOUQING_LIANJIE', '', false);
View::assign("strPcPath", '');
if ($this->TemplatesModel['t_code'] == 'videoGpt1') {
$strRankUrlTemp = $this->UrlBuilder->rankIndex();
$strSearchListUrlTemp = $this->UrlBuilder->searchEntry();
$strHistoryUrlTemp = $this->UrlBuilder->history();
} else {
$strRankUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_RANK_INDEX_URL', '', false);
$strSearchListUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_SEARCH_LIST_URL', '', false);
$strHistoryUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_HISTORY_LIST_URL', '', false);
}
View::assign("strRankUrlTemp", $strRankUrlTemp);
View::assign("strSearchListUrlTemp", $strSearchListUrlTemp);
View::assign("strHistoryUrlTemp", $strHistoryUrlTemp);
@@ -155,33 +185,34 @@ class SiteContext
}
// 视频站点需要信息
// $strVideoCategoryIndexUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_CATEGORY_INDEX_URL', '', false);
// $strVideoSearchListUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_SEARCH_LIST_URL', '', false);
// $strVideoHistoryUrlTemp = $this->DomainModel->getFomartSubject('VIDEO_HISTORY_LIST_URL', '', false);
// View::assign("strVideoCategoryIndexUrlTemp", $strVideoCategoryIndexUrlTemp);
// View::assign("strVideoSearchListUrlTemp", $strVideoSearchListUrlTemp);
// View::assign("strVideoHistoryUrlTemp", $strVideoHistoryUrlTemp);
// var_dump($this->DomainModel->t_cfg);
$strEmail = SystemConfigModel::getValByCode('YOU_XIANG');
// 1. 站点 DNA
$TpStyle = SiteStyle::getConfig();
$TpStyle = $this->TpStyle;
// 3. 构建本域名 CSS合并并替换 __PFX__
$cssUrl = CssBuilder::build(
$strCssUrl = CssBuilder::build(
$TpStyle['css_files'],
$TpStyle['dom_prefix'],
$TpStyle['static_hash']
);
$strJsUrl = JsBuilder::build(
$TpStyle['js_files'] ?? [],
(string)$TpStyle['dom_prefix'],
(string)$TpStyle['static_hash']
);
// 4. 模板变量注入
View::assign('TpStyle', $TpStyle);
View::assign("TpTpl", $TpStyle['templates']);
View::assign('TpCss', $cssUrl);
View::assign('strTpCss', $strCssUrl);
View::assign('strTpJs', $strJsUrl);
View::assign('strEmail', $strEmail);
$vod_list = $this->DomainModel;
View::assign('vod_list',$vod_list);
// View::assign('Url', new UrlBuilder($TpStyle));
$vod_list = $this->DomainModel;
View::assign('vod_list', $vod_list);
View::assign('Request', $this->Request);
View::assign('DomainModel', $this->DomainModel);
@@ -702,4 +733,75 @@ class SiteContext
return $this->Request->ip(); // 备用
}
/**
* SEO 输出统一入口(给模板标签用)
*
* @param string $strCode title | keywords | description
* @return string
*/
public function getSeoTkd(string $strCode, string $strPage): string
{
// TpStyle 已在 initCfg() 中注入
$TpStyle = $this->TpStyle;
if (empty($TpStyle)) {
return '';
}
// 1⃣ 选 SEO 模板
$renderer = new SeoRenderer($TpStyle);
$tpl = $renderer->getTemplate($strCode, $strPage);
if ($tpl === '') {
return '';
}
// var_dump($tpl);
// 2⃣ 统一走 Converter你现有系统
return ConverterMovel::convert($tpl);
}
public function getTemplate(): string
{
$strDomain = $this->Request->rootDomain();
$this->DomainModel = DomainModel::getDomainOnCacheByDomain($strDomain);
if (empty($this->DomainModel)) {
throw new HttpException(404, 'Site config not Found');
}
$this->TemplatesModel = TemplatesModel::getTemplateOnCacheByTId($this->DomainModel->t_id);
if (empty($this->TemplatesModel)) {
throw new HttpException(500, 'Site template not Found');
}
return $this->TemplatesModel['t_code'];
}
public function getPinlunData(int $intVideoId): array
{
$strDomain = $this->DomainModel->d_domain ?? request()->domain();
// 兜底:如果上下文没有 vo至少保证有 v_id占位符会降级
if (empty($vo) || intval($vo['v_id'] ?? 0) !== $intVideoId) {
$vo = ['v_id' => $intVideoId];
}
// // 冻结 cfg你也可以改成 domainSeed / pageSeed这里用你现有 seed
$arrPinlunCfg = $this->TpStyle['template_cfg']['pages']['detail']['pinlun'];
$arrPinlun = CommentPool::build(
$strDomain,
$intVideoId,
$arrPinlunCfg,
[
'v_name' => ConverterMovel::getVal('strVideoName') ?? '',
'v_actor' => ConverterMovel::getVal('strVideoActor') ?? [],
'v_director' => ConverterMovel::getVal('strVideoDirector') ?? [],
]
);
return [
'arrPinlun' => $arrPinlun,
];
}
}

View File

@@ -334,7 +334,7 @@ class StaticConfig
}
/**
* getNovelCategoryFilter
* 获取所有分类 一维数组1级+2级
*
* @return array
*/
@@ -344,7 +344,7 @@ class StaticConfig
}
/**
* getVideoCategoryTypeFilter
* 获取自定义所有分类 二维数组1级>2级
*
* @return array
*/
@@ -352,4 +352,5 @@ class StaticConfig
{
return VideoCategoryModel::getCustomCategory($strType);
}
}

View File

@@ -11,6 +11,9 @@ use app\model\VideoClicksModel;
use app\model\VideoModel;
use template\page\CusteomPage02;
use think\exception\HttpException;
use app\common\helper\SiteStyle;
use app\common\helper\UrlBuilder;
class VideoService
{
@@ -50,13 +53,19 @@ class VideoService
*/
public function getVideoCategoryIndexUrl(string $strParentCategory): string
{
$strKey = 'VIDEO_CATEGORY_INDEX_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : '',
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->categoryParent($strParentCategory);
} else {
$strKey = 'VIDEO_CATEGORY_INDEX_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : '',
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
}
}
@@ -70,31 +79,43 @@ class VideoService
*/
public function getVideoInfoUrl(int $intVId, string $strPinYin): string
{
$strKey = 'VIDEO_INFO_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $strPinYin
]);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->detail($strPinYin, $intVId);
} else {
$strKey = 'VIDEO_INFO_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $strPinYin
]);
return (string)$strUrl;
}
}
/**
* 伪造视频
*
* @param integer $intVId
* @param string $intPinYin
* @param string $strPinYin
* @param integer $intVForgeId
* @return string
*/
public function getForgeVideoInfoUrl(int $intVId, string $intPinYin, int $intVForgeId): string
public function getForgeVideoInfoUrl(int $intVId, string $strPinYin, int $intVForgeId): string
{
$strKey = 'FORGE_VIDEO_INFO_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $intPinYin,
'intVForgeId' => $intVForgeId,
]);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->detailForge($strPinYin, $intVId, $intVForgeId);
} else {
$strKey = 'FORGE_VIDEO_INFO_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $strPinYin,
'intVForgeId' => $intVForgeId,
]);
return (string)$strUrl;
}
}
/**
@@ -108,14 +129,20 @@ class VideoService
*/
public function getVideoPlayUrl(int $intVId, string $strPinYin, string $strPlayType, int $intPlayIndex): string
{
$strKey = 'VIDEO_PLAY_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $strPinYin,
'strPlayType' => $strPlayType,
'intPlayIndex' => $intPlayIndex,
]);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->play($strPinYin, $intVId, $strPlayType, $intPlayIndex);
} else {
$strKey = 'VIDEO_PLAY_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intVId' => $intVId,
'strPinYin' => $strPinYin,
'strPlayType' => $strPlayType,
'intPlayIndex' => $intPlayIndex,
]);
return (string)$strUrl;
}
}
@@ -133,19 +160,25 @@ class VideoService
*/
public function getVideoCategoryUrl(string|NULL $strCategory, string|NULL $strParentCategory, string|NULL $strArea, int|string|NULL $strLang, int|string|NULL $strYear, int|string|NULL $strOrder, int|string|NULL $intPage): string
{
$strKey = 'VIDEO_CATEGORY_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strCategory' => !empty($strCategory) ? $strCategory : 'all',
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : 'all',
'strArea' => !empty($strCategory) ? $strArea : 'all',
'strLang' => !empty($strCategory) ? $strLang : 'all',
'strYear' => !empty($strCategory) ? $strYear : 'all',
'strOrder' => !empty($strOrder) ? $strOrder : 'all',
'intPage' => $intPage ?? 1,
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->categoryChild($strParentCategory, $strCategory, $intPage);
} else {
$strKey = 'VIDEO_CATEGORY_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strCategory' => !empty($strCategory) ? $strCategory : 'all',
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : 'all',
'strArea' => !empty($strCategory) ? $strArea : 'all',
'strLang' => !empty($strCategory) ? $strLang : 'all',
'strYear' => !empty($strCategory) ? $strYear : 'all',
'strOrder' => !empty($strOrder) ? $strOrder : 'all',
'intPage' => $intPage ?? 1,
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
}
}
/**
@@ -159,17 +192,22 @@ class VideoService
*/
public function getVideoRankUrl(string $strCategory, string $strParentCategory, string $strSortType, int $intPage): string
{
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
$strKey = 'VIDEO_RANK_LIST_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strCategory' => !empty($strCategory) ? $strCategory : 'all',
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : 'all',
'strSortType' => !empty($strSortType) ? $strSortType : 'all',
'intPage' => $intPage ?? 1,
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->rankList($strSortType);
} else {
$strKey = 'VIDEO_RANK_LIST_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'strCategory' => !empty($strCategory) ? $strCategory : 'all',
'strParentCategory' => !empty($strParentCategory) ? $strParentCategory : 'all',
'strSortType' => !empty($strSortType) ? $strSortType : 'all',
'intPage' => $intPage ?? 1,
]);
$strUrl = (string)($strUrl ?? '');
$strUrl = preg_replace('#/{2,}#', '/', $strUrl);
return (string)$strUrl;
}
}
@@ -203,12 +241,18 @@ class VideoService
*/
public function getVideoSearchUrl($strKeyWords, $intPage = 1): string
{
$strKey = 'VIDEO_SEARCH_LIST_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intPage' => $intPage,
'strSearchKeywords' => $strKeyWords
]);
return (string)$strUrl;
$strTmpCode = $this->SiteContext->TemplatesModel['t_code'];
if ($strTmpCode == 'videoGpt1') {
return $this->SiteContext->UrlBuilder->searchResult($strKeyWords);
} else {
$strKey = 'VIDEO_SEARCH_LIST_URL';
$strUrl = $this->SiteContext->DomainModel->getFomartUrl($strKey, [
'intPage' => $intPage,
'strSearchKeywords' => $strKeyWords
]);
return (string)$strUrl;
}
}
/**
@@ -608,6 +652,8 @@ class VideoService
}
// 更新值
$arrAllVideoClass = StaticConfig::getVideoCategoryFilter();
$strNCategory = $arrAllVideoClass[$strVCategoryEn];
ConverterMovel::setVal([
'intPage' => $intPage,
@@ -746,4 +792,137 @@ class VideoService
return $arrVideo;
}
/**
* 获取 播放线路-中文
*
* @param string $strCode
* @return string
*/
public function getConverterPlayLineVal(string $strCode): string
{
$strCode = strtolower(trim((string)$strCode));
if ($strCode === '') {
return '默认';
}
// 线路映射(可持续扩展)
$arrMap = [
'maotai' => '茅台',
'douban' => '豆瓣',
'youzhi' => '优质',
'default' => '默认',
'vip' => 'VIP线路',
];
if (isset($arrMap[$strCode])) {
return $arrMap[$strCode];
}
// 标准化(去空格)
$strNorm = preg_replace('/\s+/', '', $strCode);
if ($strNorm === '') {
return '默认';
}
// yun-2 / yun_2
if (preg_match('/^([a-z]+)[\-_](\d+)$/', $strNorm, $arrMatch)) {
$strPrefix = $arrMatch[1];
$intNum = (int)$arrMatch[2];
$strPrefixName = $arrMap[$strPrefix] ?? strtoupper($strPrefix);
return $strPrefixName . ' ' . $intNum;
}
// yun3 / vip2
if (preg_match('/^([a-z]+)(\d+)$/', $strNorm, $arrMatch)) {
$strPrefix = $arrMatch[1];
$intNum = (int)$arrMatch[2];
$strPrefixName = $arrMap[$strPrefix] ?? strtoupper($strPrefix);
return $strPrefixName . ' ' . $intNum;
}
// 未命中变得更可读abc-def → Abc Def
$strHuman = preg_replace('/[\-_]+/', ' ', $strNorm);
$strHuman = trim((string)$strHuman);
if ($strHuman !== '') {
return ucwords($strHuman);
}
return '默认';
}
/**
* 获取图片 alt稳定、域名级差异、同片稳定
*
* @param array $arrTpStyle
* @param array|object $arrVideo 支持 array / BSONDocument
* @param string $strSlotType detail_cover | list_poster ...
* @param string $strItemType poster | media | rank ...
* @return string
*/
public function getVideoImgAlt(array $arrTpStyle, $arrVideo, string $strSlotType = 'list_poster', string $strItemType = 'poster'): string
{
$arrVideo = $this->toArraySafe($arrVideo);
return SiteStyle::buildImgAlt($arrTpStyle, $arrVideo, $strSlotType, $strItemType);
}
/**
* 获取详情页“防薄内容”模块数据(稳定、域名级差异、同片稳定)
*
* @param array $arrTpStyle
* @param array $arrVideo
* @return array
*/
public function getVideoDetailSeoAddon(array $arrTpStyle, array $arrVideo): array
{
return SiteStyle::buildDetailSeoAddon($arrTpStyle, $arrVideo);
}
/**
* BSONDocument / 对象 / array 统一转数组(递归)
*/
private function toArraySafe($mixVal): array
{
if (is_array($mixVal)) return $mixVal;
// MongoDB BSONDocument / BSONArray 通常实现了 getArrayCopy 或 jsonSerialize
if (is_object($mixVal)) {
if (method_exists($mixVal, 'getArrayCopy')) {
return $this->toArrayDeep($mixVal->getArrayCopy());
}
if ($mixVal instanceof \JsonSerializable) {
$tmp = $mixVal->jsonSerialize();
return $this->toArrayDeep(is_array($tmp) ? $tmp : (array)$tmp);
}
return $this->toArrayDeep((array)$mixVal);
}
return [];
}
private function toArrayDeep($mixVal)
{
if (!is_array($mixVal)) return $mixVal;
foreach ($mixVal as $k => $v) {
if (is_object($v)) {
if (method_exists($v, 'getArrayCopy')) {
$mixVal[$k] = $this->toArrayDeep($v->getArrayCopy());
} elseif ($v instanceof \JsonSerializable) {
$tmp = $v->jsonSerialize();
$mixVal[$k] = $this->toArrayDeep(is_array($tmp) ? $tmp : (array)$tmp);
} else {
$mixVal[$k] = $this->toArrayDeep((array)$v);
}
} elseif (is_array($v)) {
$mixVal[$k] = $this->toArrayDeep($v);
}
}
return $mixVal;
}
}