修复私人影库报错导致搜索无结果

This commit is contained in:
mtvpls
2026-01-07 01:08:55 +08:00
parent b0e4d3c624
commit 227d1370da
2 changed files with 142 additions and 122 deletions
+67 -57
View File
@@ -55,34 +55,39 @@ export async function GET(request: NextRequest) {
const embyPromise = hasEmby const embyPromise = hasEmby
? Promise.race([ ? Promise.race([
(async () => { (async () => {
const { EmbyClient } = await import('@/lib/emby.client'); try {
const client = new EmbyClient(config.EmbyConfig!); const { EmbyClient } = await import('@/lib/emby.client');
const searchResult = await client.getItems({ const client = new EmbyClient(config.EmbyConfig!);
searchTerm: query, const searchResult = await client.getItems({
IncludeItemTypes: 'Movie,Series', searchTerm: query,
Recursive: true, IncludeItemTypes: 'Movie,Series',
Fields: 'Overview,ProductionYear', Recursive: true,
Limit: 50, Fields: 'Overview,ProductionYear',
}); Limit: 50,
return searchResult.Items.map((item) => ({ });
id: item.Id, return searchResult.Items.map((item) => ({
source: 'emby', id: item.Id,
source_name: 'Emby', source: 'emby',
title: item.Name, source_name: 'Emby',
poster: client.getImageUrl(item.Id, 'Primary'), title: item.Name,
episodes: [], poster: client.getImageUrl(item.Id, 'Primary'),
episodes_titles: [], episodes: [],
year: item.ProductionYear?.toString() || '', episodes_titles: [],
desc: item.Overview || '', year: item.ProductionYear?.toString() || '',
type_name: item.Type === 'Movie' ? '电影' : '电视剧', desc: item.Overview || '',
douban_id: 0, type_name: item.Type === 'Movie' ? '电影' : '电视剧',
})); douban_id: 0,
}));
} catch (error) {
console.error('[Search] 搜索 Emby 失败:', error);
return [];
}
})(), })(),
new Promise<any[]>((_, reject) => new Promise<any[]>((_, reject) =>
setTimeout(() => reject(new Error('Emby timeout')), 20000) setTimeout(() => reject(new Error('Emby timeout')), 20000)
), ),
]).catch((error) => { ]).catch((error) => {
console.error('[Search] 搜索 Emby 失败:', error); console.error('[Search] 搜索 Emby 超时:', error);
return []; return [];
}) })
: Promise.resolve([]); : Promise.resolve([]);
@@ -91,51 +96,56 @@ export async function GET(request: NextRequest) {
const openlistPromise = hasOpenList const openlistPromise = hasOpenList
? Promise.race([ ? Promise.race([
(async () => { (async () => {
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache'); try {
const { getTMDBImageUrl } = await import('@/lib/tmdb.search'); const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
const { db } = await import('@/lib/db'); const { getTMDBImageUrl } = await import('@/lib/tmdb.search');
const { db } = await import('@/lib/db');
const rootPath = config.OpenListConfig!.RootPath || '/'; const rootPath = config.OpenListConfig!.RootPath || '/';
let metaInfo = getCachedMetaInfo(rootPath); let metaInfo = getCachedMetaInfo(rootPath);
if (!metaInfo) { if (!metaInfo) {
const metainfoJson = await db.getGlobalValue('video.metainfo'); const metainfoJson = await db.getGlobalValue('video.metainfo');
if (metainfoJson) { if (metainfoJson) {
metaInfo = JSON.parse(metainfoJson); metaInfo = JSON.parse(metainfoJson);
if (metaInfo) { if (metaInfo) {
setCachedMetaInfo(rootPath, metaInfo); setCachedMetaInfo(rootPath, metaInfo);
}
} }
} }
}
if (metaInfo && metaInfo.folders) { if (metaInfo && metaInfo.folders) {
return Object.entries(metaInfo.folders) return Object.entries(metaInfo.folders)
.filter(([folderName, info]: [string, any]) => { .filter(([folderName, info]: [string, any]) => {
const matchFolder = folderName.toLowerCase().includes(query.toLowerCase()); const matchFolder = folderName.toLowerCase().includes(query.toLowerCase());
const matchTitle = info.title.toLowerCase().includes(query.toLowerCase()); const matchTitle = info.title.toLowerCase().includes(query.toLowerCase());
return matchFolder || matchTitle; return matchFolder || matchTitle;
}) })
.map(([folderName, info]: [string, any]) => ({ .map(([folderName, info]: [string, any]) => ({
id: folderName, id: folderName,
source: 'openlist', source: 'openlist',
source_name: '私人影库', source_name: '私人影库',
title: info.title, title: info.title,
poster: getTMDBImageUrl(info.poster_path), poster: getTMDBImageUrl(info.poster_path),
episodes: [], episodes: [],
episodes_titles: [], episodes_titles: [],
year: info.release_date.split('-')[0] || '', year: info.release_date.split('-')[0] || '',
desc: info.overview, desc: info.overview,
type_name: info.media_type === 'movie' ? '电影' : '电视剧', type_name: info.media_type === 'movie' ? '电影' : '电视剧',
douban_id: 0, douban_id: 0,
})); }));
}
return [];
} catch (error) {
console.error('[Search] 搜索 OpenList 失败:', error);
return [];
} }
return [];
})(), })(),
new Promise<any[]>((_, reject) => new Promise<any[]>((_, reject) =>
setTimeout(() => reject(new Error('OpenList timeout')), 20000) setTimeout(() => reject(new Error('OpenList timeout')), 20000)
), ),
]).catch((error) => { ]).catch((error) => {
console.error('[Search] 搜索 OpenList 失败:', error); console.error('[Search] 搜索 OpenList 超时:', error);
return []; return [];
}) })
: Promise.resolve([]); : Promise.resolve([]);
+75 -65
View File
@@ -93,28 +93,33 @@ export async function GET(request: NextRequest) {
if (hasEmby) { if (hasEmby) {
Promise.race([ Promise.race([
(async () => { (async () => {
const { EmbyClient } = await import('@/lib/emby.client'); try {
const client = new EmbyClient(config.EmbyConfig!); const { EmbyClient } = await import('@/lib/emby.client');
const searchResult = await client.getItems({ const client = new EmbyClient(config.EmbyConfig!);
searchTerm: query, const searchResult = await client.getItems({
IncludeItemTypes: 'Movie,Series', searchTerm: query,
Recursive: true, IncludeItemTypes: 'Movie,Series',
Fields: 'Overview,ProductionYear', Recursive: true,
Limit: 50, Fields: 'Overview,ProductionYear',
}); Limit: 50,
return searchResult.Items.map((item) => ({ });
id: item.Id, return searchResult.Items.map((item) => ({
source: 'emby', id: item.Id,
source_name: 'Emby', source: 'emby',
title: item.Name, source_name: 'Emby',
poster: client.getImageUrl(item.Id, 'Primary'), title: item.Name,
episodes: [], poster: client.getImageUrl(item.Id, 'Primary'),
episodes_titles: [], episodes: [],
year: item.ProductionYear?.toString() || '', episodes_titles: [],
desc: item.Overview || '', year: item.ProductionYear?.toString() || '',
type_name: item.Type === 'Movie' ? '电影' : '电视剧', desc: item.Overview || '',
douban_id: 0, type_name: item.Type === 'Movie' ? '电影' : '电视剧',
})); douban_id: 0,
}));
} catch (error) {
console.error('[Search WS] 搜索 Emby 失败:', error);
return [];
}
})(), })(),
new Promise((_, reject) => new Promise((_, reject) =>
setTimeout(() => reject(new Error('Emby timeout')), 20000) setTimeout(() => reject(new Error('Emby timeout')), 20000)
@@ -140,17 +145,17 @@ export async function GET(request: NextRequest) {
} }
}) })
.catch((error) => { .catch((error) => {
console.error('[Search WS] 搜索 Emby 失败:', error); console.error('[Search WS] 搜索 Emby 超时:', error);
completedSources++; completedSources++;
if (!streamClosed) { if (!streamClosed) {
const errorEvent = `data: ${JSON.stringify({ const sourceEvent = `data: ${JSON.stringify({
type: 'source_error', type: 'source_result',
source: 'emby', source: 'emby',
sourceName: 'Emby', sourceName: 'Emby',
error: error instanceof Error ? error.message : '搜索失败', results: [],
timestamp: Date.now() timestamp: Date.now()
})}\n\n`; })}\n\n`;
safeEnqueue(encoder.encode(errorEvent)); safeEnqueue(encoder.encode(sourceEvent));
} }
}); });
} }
@@ -159,45 +164,50 @@ export async function GET(request: NextRequest) {
if (hasOpenList) { if (hasOpenList) {
Promise.race([ Promise.race([
(async () => { (async () => {
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache'); try {
const { getTMDBImageUrl } = await import('@/lib/tmdb.search'); const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
const { db } = await import('@/lib/db'); const { getTMDBImageUrl } = await import('@/lib/tmdb.search');
const { db } = await import('@/lib/db');
const rootPath = config.OpenListConfig!.RootPath || '/'; const rootPath = config.OpenListConfig!.RootPath || '/';
let metaInfo = getCachedMetaInfo(rootPath); let metaInfo = getCachedMetaInfo(rootPath);
if (!metaInfo) { if (!metaInfo) {
const metainfoJson = await db.getGlobalValue('video.metainfo'); const metainfoJson = await db.getGlobalValue('video.metainfo');
if (metainfoJson) { if (metainfoJson) {
metaInfo = JSON.parse(metainfoJson); metaInfo = JSON.parse(metainfoJson);
if (metaInfo) { if (metaInfo) {
setCachedMetaInfo(rootPath, metaInfo); setCachedMetaInfo(rootPath, metaInfo);
}
} }
} }
}
if (metaInfo && metaInfo.folders) { if (metaInfo && metaInfo.folders) {
return Object.entries(metaInfo.folders) return Object.entries(metaInfo.folders)
.filter(([key, info]: [string, any]) => { .filter(([key, info]: [string, any]) => {
const matchFolder = info.folderName.toLowerCase().includes(query.toLowerCase()); const matchFolder = info.folderName.toLowerCase().includes(query.toLowerCase());
const matchTitle = info.title.toLowerCase().includes(query.toLowerCase()); const matchTitle = info.title.toLowerCase().includes(query.toLowerCase());
return matchFolder || matchTitle; return matchFolder || matchTitle;
}) })
.map(([key, info]: [string, any]) => ({ .map(([key, info]: [string, any]) => ({
id: key, id: key,
source: 'openlist', source: 'openlist',
source_name: '私人影库', source_name: '私人影库',
title: info.title, title: info.title,
poster: getTMDBImageUrl(info.poster_path), poster: getTMDBImageUrl(info.poster_path),
episodes: [], episodes: [],
episodes_titles: [], episodes_titles: [],
year: info.release_date.split('-')[0] || '', year: info.release_date.split('-')[0] || '',
desc: info.overview, desc: info.overview,
type_name: info.media_type === 'movie' ? '电影' : '电视剧', type_name: info.media_type === 'movie' ? '电影' : '电视剧',
douban_id: 0, douban_id: 0,
})); }));
}
return [];
} catch (error) {
console.error('[Search WS] 搜索 OpenList 失败:', error);
return [];
} }
return [];
})(), })(),
new Promise((_, reject) => new Promise((_, reject) =>
setTimeout(() => reject(new Error('OpenList timeout')), 20000) setTimeout(() => reject(new Error('OpenList timeout')), 20000)
@@ -223,17 +233,17 @@ export async function GET(request: NextRequest) {
} }
}) })
.catch((error) => { .catch((error) => {
console.error('[Search WS] 搜索 OpenList 失败:', error); console.error('[Search WS] 搜索 OpenList 超时:', error);
completedSources++; completedSources++;
if (!streamClosed) { if (!streamClosed) {
const errorEvent = `data: ${JSON.stringify({ const sourceEvent = `data: ${JSON.stringify({
type: 'source_error', type: 'source_result',
source: 'openlist', source: 'openlist',
sourceName: '私人影库', sourceName: '私人影库',
error: error instanceof Error ? error.message : '搜索失败', results: [],
timestamp: Date.now() timestamp: Date.now()
})}\n\n`; })}\n\n`;
safeEnqueue(encoder.encode(errorEvent)); safeEnqueue(encoder.encode(sourceEvent));
} }
}); });
} }