修复私人影库从搜索进无法播放,优化完结标识判断

This commit is contained in:
mtvpls
2025-12-24 20:05:58 +08:00
parent 4678715b77
commit 187e6f1bd4
2 changed files with 106 additions and 22 deletions

View File

@@ -36,6 +36,61 @@ export async function GET(request: NextRequest) {
const config = await getConfig();
const apiSites = await getAvailableApiSites(authInfo.username);
// 检查是否配置了 OpenList
const hasOpenList = !!(config.OpenListConfig?.URL && config.OpenListConfig?.Username && config.OpenListConfig?.Password);
// 搜索 OpenList如果配置了
let openlistResults: any[] = [];
if (hasOpenList) {
try {
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
const { getTMDBImageUrl } = await import('@/lib/tmdb.search');
const { db } = await import('@/lib/db');
const rootPath = config.OpenListConfig!.RootPath || '/';
let metaInfo = getCachedMetaInfo(rootPath);
// 如果没有缓存,尝试从数据库读取
if (!metaInfo) {
try {
const metainfoJson = await db.getGlobalValue('video.metainfo');
if (metainfoJson) {
metaInfo = JSON.parse(metainfoJson);
if (metaInfo) {
setCachedMetaInfo(rootPath, metaInfo);
}
}
} catch (error) {
console.error('[Search] 从数据库读取 metainfo 失败:', error);
}
}
if (metaInfo && metaInfo.folders) {
openlistResults = Object.entries(metaInfo.folders)
.filter(([folderName, info]: [string, any]) => {
const matchFolder = folderName.toLowerCase().includes(query.toLowerCase());
const matchTitle = info.title.toLowerCase().includes(query.toLowerCase());
return matchFolder || matchTitle;
})
.map(([folderName, info]: [string, any]) => ({
id: folderName,
source: 'openlist',
source_name: '私人影库',
title: info.title,
poster: getTMDBImageUrl(info.poster_path),
episodes: [],
episodes_titles: [],
year: info.release_date.split('-')[0] || '',
desc: info.overview,
type_name: info.media_type === 'movie' ? '电影' : '电视剧',
douban_id: 0,
}));
}
} catch (error) {
console.error('[Search] 搜索 OpenList 失败:', error);
}
}
// 添加超时控制和错误处理,避免慢接口拖累整体响应
const searchPromises = apiSites.map((site) =>
Promise.race([
@@ -54,7 +109,7 @@ export async function GET(request: NextRequest) {
const successResults = results
.filter((result) => result.status === 'fulfilled')
.map((result) => (result as PromiseFulfilledResult<any>).value);
let flattenedResults = successResults.flat();
let flattenedResults = [...openlistResults, ...successResults.flat()];
if (!config.SiteConfig.DisableYellowFilter) {
flattenedResults = flattenedResults.filter((result) => {
const typeName = result.type_name || '';

View File

@@ -606,9 +606,9 @@ function PlayPageClient() {
// 工具函数Utils
// -----------------------------------------------------------------------------
// 判断剧集是否已完结
const isSeriesCompleted = (detail: SearchResult | null): boolean => {
if (!detail) return false;
// 判断剧集状态
const getSeriesStatus = (detail: SearchResult | null): 'completed' | 'ongoing' | 'unknown' => {
if (!detail) return 'unknown';
// 方法1通过 vod_remarks 判断
if (detail.vod_remarks) {
@@ -620,23 +620,27 @@ function PlayPageClient() {
// 如果包含连载关键词,则为连载中
if (ongoingKeywords.some(keyword => remarks.includes(keyword))) {
return false;
return 'ongoing';
}
// 如果包含完结关键词,则为已完结
if (completedKeywords.some(keyword => remarks.includes(keyword))) {
return true;
return 'completed';
}
}
// 方法2通过 vod_total 和实际集数对比判断
if (detail.vod_total && detail.vod_total > 0 && detail.episodes && detail.episodes.length > 0) {
// 如果实际集数 >= 总集数,则为已完结
return detail.episodes.length >= detail.vod_total;
if (detail.episodes.length >= detail.vod_total) {
return 'completed';
}
// 如果实际集数 < 总集数,则为连载中
return 'ongoing';
}
// 无法判断,默认返回 false连载中
return false;
// 无法判断,返回 unknown
return 'unknown';
};
// 播放源优选函数
@@ -1776,7 +1780,9 @@ function PlayPageClient() {
? result.year.toLowerCase() === videoYearRef.current.toLowerCase()
: true) &&
(searchType
? (searchType === 'tv' && result.episodes.length > 1) ||
? // openlist 源跳过 episodes 长度检查,因为搜索时不返回详细播放列表
result.source === 'openlist' ||
(searchType === 'tv' && result.episodes.length > 1) ||
(searchType === 'movie' && result.episodes.length === 1)
: true)
);
@@ -1829,6 +1835,15 @@ function PlayPageClient() {
);
if (target) {
detailData = target;
// 如果是 openlist 源且 episodes 为空,需要调用 detail 接口获取完整信息
if (detailData.source === 'openlist' && (!detailData.episodes || detailData.episodes.length === 0)) {
console.log('[Play] OpenList source has no episodes, fetching detail...');
const detailSources = await fetchSourceDetail(currentSource, currentId);
if (detailSources.length > 0) {
detailData = detailSources[0];
}
}
} else {
setError('未找到匹配结果');
setLoading(false);
@@ -1849,6 +1864,15 @@ function PlayPageClient() {
console.log(detailData.source, detailData.id);
// 如果是 openlist 源且 episodes 为空,需要调用 detail 接口获取完整信息
if (detailData.source === 'openlist' && (!detailData.episodes || detailData.episodes.length === 0)) {
console.log('[Play] OpenList source has no episodes after selection, fetching detail...');
const detailSources = await fetchSourceDetail(detailData.source, detailData.id);
if (detailSources.length > 0) {
detailData = detailSources[0];
}
}
setNeedPrefer(false);
setCurrentSource(detailData.source);
setCurrentId(detailData.id);
@@ -2841,7 +2865,7 @@ function PlayPageClient() {
total_episodes: detailRef.current?.episodes.length || 1,
save_time: Date.now(),
search_title: searchTitle,
is_completed: isSeriesCompleted(detailRef.current),
is_completed: getSeriesStatus(detailRef.current) === 'completed',
vod_remarks: detailRef.current?.vod_remarks,
});
setFavorited(true);
@@ -4408,17 +4432,22 @@ function PlayPageClient() {
)}
</span>
{/* 完结状态标识 */}
{detail && totalEpisodes > 1 && (
<span
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
isSeriesCompleted(detail)
? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'
: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'
}`}
>
{isSeriesCompleted(detail) ? '已完结' : '连载中'}
</span>
)}
{detail && totalEpisodes > 1 && (() => {
const status = getSeriesStatus(detail);
if (status === 'unknown') return null;
return (
<span
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
status === 'completed'
? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'
: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'
}`}
>
{status === 'completed' ? '已完结' : '连载中'}
</span>
);
})()}
</h1>
</div>
{/* 第二行:播放器和选集 */}