修复私人影库报错导致搜索无结果
This commit is contained in:
+67
-57
@@ -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([]);
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user