修正立即扫描openlist端不刷新
This commit is contained in:
@@ -2569,10 +2569,11 @@ const OpenListConfigComponent = ({
|
|||||||
}
|
}
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
const fetchVideos = async () => {
|
const fetchVideos = async (noCache = false) => {
|
||||||
try {
|
try {
|
||||||
setRefreshing(true);
|
setRefreshing(true);
|
||||||
const response = await fetch('/api/openlist/list?page=1&pageSize=100&includeFailed=true');
|
const url = `/api/openlist/list?page=1&pageSize=100&includeFailed=true${noCache ? '&noCache=true' : ''}`;
|
||||||
|
const response = await fetch(url);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setVideos(data.list || []);
|
setVideos(data.list || []);
|
||||||
@@ -2658,8 +2659,10 @@ const OpenListConfigComponent = ({
|
|||||||
`扫描完成!新增 ${task.result.new} 个,已存在 ${task.result.existing} 个,失败 ${task.result.errors} 个`,
|
`扫描完成!新增 ${task.result.new} 个,已存在 ${task.result.existing} 个,失败 ${task.result.errors} 个`,
|
||||||
showAlert
|
showAlert
|
||||||
);
|
);
|
||||||
|
// 先强制从数据库读取视频列表(这会更新缓存)
|
||||||
|
await fetchVideos(true);
|
||||||
|
// 然后再刷新配置(这会触发 useEffect,但此时缓存已经是新的了)
|
||||||
await refreshConfig();
|
await refreshConfig();
|
||||||
await fetchVideos();
|
|
||||||
} else if (task.status === 'failed') {
|
} else if (task.status === 'failed') {
|
||||||
clearInterval(pollInterval);
|
clearInterval(pollInterval);
|
||||||
setScanProgress(null);
|
setScanProgress(null);
|
||||||
@@ -2703,7 +2706,7 @@ const OpenListConfigComponent = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCorrectSuccess = () => {
|
const handleCorrectSuccess = () => {
|
||||||
fetchVideos();
|
fetchVideos(true); // 强制从数据库重新读取,不使用缓存
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDate = (timestamp?: number) => {
|
const formatDate = (timestamp?: number) => {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { getTMDBImageUrl } from '@/lib/tmdb.search';
|
|||||||
export const runtime = 'nodejs';
|
export const runtime = 'nodejs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /api/openlist/list?page=1&pageSize=20&includeFailed=false
|
* GET /api/openlist/list?page=1&pageSize=20&includeFailed=false&noCache=false
|
||||||
* 获取私人影库视频列表
|
* 获取私人影库视频列表
|
||||||
*/
|
*/
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
@@ -30,6 +30,7 @@ export async function GET(request: NextRequest) {
|
|||||||
const page = parseInt(searchParams.get('page') || '1');
|
const page = parseInt(searchParams.get('page') || '1');
|
||||||
const pageSize = parseInt(searchParams.get('pageSize') || '20');
|
const pageSize = parseInt(searchParams.get('pageSize') || '20');
|
||||||
const includeFailed = searchParams.get('includeFailed') === 'true';
|
const includeFailed = searchParams.get('includeFailed') === 'true';
|
||||||
|
const noCache = searchParams.get('noCache') === 'true';
|
||||||
|
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
const openListConfig = config.OpenListConfig;
|
const openListConfig = config.OpenListConfig;
|
||||||
@@ -49,30 +50,22 @@ export async function GET(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 读取 metainfo (从数据库或缓存)
|
// 读取 metainfo (从数据库或缓存)
|
||||||
let metaInfo: MetaInfo | null = getCachedMetaInfo(rootPath);
|
let metaInfo: MetaInfo | null = null;
|
||||||
|
|
||||||
console.log('[OpenList List] 缓存检查:', {
|
// 如果不使用缓存,直接从数据库读取
|
||||||
rootPath,
|
if (noCache) {
|
||||||
hasCachedMetaInfo: !!metaInfo,
|
// noCache 模式:跳过缓存
|
||||||
});
|
} else {
|
||||||
|
metaInfo = getCachedMetaInfo(rootPath);
|
||||||
|
}
|
||||||
|
|
||||||
if (!metaInfo) {
|
if (!metaInfo) {
|
||||||
try {
|
try {
|
||||||
console.log('[OpenList List] 尝试从数据库读取 metainfo');
|
|
||||||
|
|
||||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||||
|
|
||||||
if (metainfoJson) {
|
if (metainfoJson) {
|
||||||
console.log('[OpenList List] 从数据库获取到数据,长度:', metainfoJson.length);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
metaInfo = JSON.parse(metainfoJson);
|
metaInfo = JSON.parse(metainfoJson);
|
||||||
console.log('[OpenList List] JSON 解析成功');
|
|
||||||
console.log('[OpenList List] metaInfo 结构:', {
|
|
||||||
hasfolders: !!metaInfo?.folders,
|
|
||||||
foldersType: typeof metaInfo?.folders,
|
|
||||||
keys: metaInfo?.folders ? Object.keys(metaInfo.folders) : [],
|
|
||||||
});
|
|
||||||
|
|
||||||
// 验证数据结构
|
// 验证数据结构
|
||||||
if (!metaInfo || typeof metaInfo !== 'object') {
|
if (!metaInfo || typeof metaInfo !== 'object') {
|
||||||
@@ -82,8 +75,10 @@ export async function GET(request: NextRequest) {
|
|||||||
throw new Error('metaInfo.folders 不存在或不是对象');
|
throw new Error('metaInfo.folders 不存在或不是对象');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[OpenList List] 解析成功,视频数量:', Object.keys(metaInfo.folders).length);
|
// 只有在不是 noCache 模式时才更新缓存
|
||||||
setCachedMetaInfo(rootPath, metaInfo);
|
if (!noCache) {
|
||||||
|
setCachedMetaInfo(rootPath, metaInfo);
|
||||||
|
}
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.error('[OpenList List] JSON 解析或验证失败:', parseError);
|
console.error('[OpenList List] JSON 解析或验证失败:', parseError);
|
||||||
throw new Error(`JSON 解析失败: ${(parseError as Error).message}`);
|
throw new Error(`JSON 解析失败: ${(parseError as Error).message}`);
|
||||||
@@ -106,7 +101,6 @@ export async function GET(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!metaInfo) {
|
if (!metaInfo) {
|
||||||
console.error('[OpenList List] metaInfo 为 null');
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: '无数据', list: [], total: 0 },
|
{ error: '无数据', list: [], total: 0 },
|
||||||
{ status: 200 }
|
{ status: 200 }
|
||||||
@@ -115,19 +109,12 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
// 验证 metaInfo 结构
|
// 验证 metaInfo 结构
|
||||||
if (!metaInfo.folders || typeof metaInfo.folders !== 'object') {
|
if (!metaInfo.folders || typeof metaInfo.folders !== 'object') {
|
||||||
console.error('[OpenList List] metaInfo.folders 无效:', {
|
|
||||||
hasfolders: !!metaInfo.folders,
|
|
||||||
foldersType: typeof metaInfo.folders,
|
|
||||||
metaInfoKeys: Object.keys(metaInfo),
|
|
||||||
});
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: 'metainfo.json 结构无效', list: [], total: 0 },
|
{ error: 'metainfo.json 结构无效', list: [], total: 0 },
|
||||||
{ status: 200 }
|
{ status: 200 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[OpenList List] 开始转换视频列表,视频数:', Object.keys(metaInfo.folders).length);
|
|
||||||
|
|
||||||
// 转换为数组并分页
|
// 转换为数组并分页
|
||||||
const allVideos = Object.entries(metaInfo.folders)
|
const allVideos = Object.entries(metaInfo.folders)
|
||||||
.filter(([, info]) => includeFailed || !info.failed) // 根据参数过滤失败的视频
|
.filter(([, info]) => includeFailed || !info.failed) // 根据参数过滤失败的视频
|
||||||
|
|||||||
@@ -104,59 +104,21 @@ async function performScan(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const client = new OpenListClient(url, username!, password!);
|
const client = new OpenListClient(url, username!, password!);
|
||||||
|
|
||||||
console.log('[OpenList Refresh] 开始扫描:', {
|
// 立即清除缓存,确保后续读取的是新数据
|
||||||
taskId,
|
invalidateMetaInfoCache(rootPath);
|
||||||
rootPath,
|
|
||||||
url,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 立即更新进度,确保任务可被查询
|
// 立即更新进度,确保任务可被查询
|
||||||
updateScanTaskProgress(taskId, 0, 0);
|
updateScanTaskProgress(taskId, 0, 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 读取现有 metainfo (从数据库或缓存)
|
// 1. 不读取现有数据,直接创建新的 metainfo
|
||||||
let existingMetaInfo: MetaInfo | null = getCachedMetaInfo(rootPath);
|
const metaInfo: MetaInfo = {
|
||||||
|
|
||||||
if (!existingMetaInfo) {
|
|
||||||
try {
|
|
||||||
console.log('[OpenList Refresh] 尝试从数据库读取 metainfo');
|
|
||||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
|
||||||
|
|
||||||
if (metainfoJson) {
|
|
||||||
existingMetaInfo = JSON.parse(metainfoJson);
|
|
||||||
console.log('[OpenList Refresh] 从数据库读取到现有数据:', {
|
|
||||||
hasfolders: !!existingMetaInfo?.folders,
|
|
||||||
foldersType: typeof existingMetaInfo?.folders,
|
|
||||||
videoCount: Object.keys(existingMetaInfo?.folders || {}).length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[OpenList Refresh] 从数据库读取 metainfo 失败:', error);
|
|
||||||
console.log('[OpenList Refresh] 将创建新数据');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('[OpenList Refresh] 使用缓存的 metainfo,视频数:', Object.keys(existingMetaInfo.folders).length);
|
|
||||||
}
|
|
||||||
|
|
||||||
const metaInfo: MetaInfo = existingMetaInfo || {
|
|
||||||
folders: {},
|
folders: {},
|
||||||
last_refresh: Date.now(),
|
last_refresh: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 确保 folders 对象存在
|
// 2. 列出根目录下的所有文件夹(强制刷新 OpenList 缓存)
|
||||||
if (!metaInfo.folders || typeof metaInfo.folders !== 'object') {
|
const listResponse = await client.listDirectory(rootPath, 1, 100, true);
|
||||||
console.warn('[OpenList Refresh] metaInfo.folders 无效,重新初始化');
|
|
||||||
metaInfo.folders = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[OpenList Refresh] metaInfo 初始化完成:', {
|
|
||||||
hasfolders: !!metaInfo.folders,
|
|
||||||
foldersType: typeof metaInfo.folders,
|
|
||||||
videoCount: Object.keys(metaInfo.folders).length,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. 列出根目录下的所有文件夹
|
|
||||||
const listResponse = await client.listDirectory(rootPath);
|
|
||||||
|
|
||||||
if (listResponse.code !== 200) {
|
if (listResponse.code !== 200) {
|
||||||
throw new Error('OpenList 列表获取失败');
|
throw new Error('OpenList 列表获取失败');
|
||||||
@@ -164,11 +126,6 @@ async function performScan(
|
|||||||
|
|
||||||
const folders = listResponse.data.content.filter((item) => item.is_dir);
|
const folders = listResponse.data.content.filter((item) => item.is_dir);
|
||||||
|
|
||||||
console.log('[OpenList Refresh] 找到文件夹:', {
|
|
||||||
total: folders.length,
|
|
||||||
names: folders.map(f => f.name),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新任务进度
|
// 更新任务进度
|
||||||
updateScanTaskProgress(taskId, 0, folders.length);
|
updateScanTaskProgress(taskId, 0, folders.length);
|
||||||
|
|
||||||
@@ -178,19 +135,11 @@ async function performScan(
|
|||||||
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
const folder = folders[i];
|
const folder = folders[i];
|
||||||
console.log('[OpenList Refresh] 处理文件夹:', folder.name);
|
|
||||||
|
|
||||||
// 更新进度
|
// 更新进度
|
||||||
updateScanTaskProgress(taskId, i + 1, folders.length, folder.name);
|
updateScanTaskProgress(taskId, i + 1, folders.length, folder.name);
|
||||||
|
|
||||||
// 跳过已搜索过的文件夹
|
|
||||||
if (metaInfo.folders[folder.name]) {
|
|
||||||
console.log('[OpenList Refresh] 跳过已存在的文件夹:', folder.name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[OpenList Refresh] 搜索 TMDB:', folder.name);
|
|
||||||
// 搜索 TMDB
|
// 搜索 TMDB
|
||||||
const searchResult = await searchTMDB(
|
const searchResult = await searchTMDB(
|
||||||
tmdbApiKey,
|
tmdbApiKey,
|
||||||
@@ -198,12 +147,6 @@ async function performScan(
|
|||||||
tmdbProxy
|
tmdbProxy
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('[OpenList Refresh] TMDB 搜索结果:', {
|
|
||||||
folder: folder.name,
|
|
||||||
code: searchResult.code,
|
|
||||||
hasResult: !!searchResult.result,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (searchResult.code === 200 && searchResult.result) {
|
if (searchResult.code === 200 && searchResult.result) {
|
||||||
const result = searchResult.result;
|
const result = searchResult.result;
|
||||||
|
|
||||||
@@ -219,14 +162,8 @@ async function performScan(
|
|||||||
failed: false,
|
failed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[OpenList Refresh] 添加成功:', {
|
|
||||||
folder: folder.name,
|
|
||||||
title: metaInfo.folders[folder.name].title,
|
|
||||||
});
|
|
||||||
|
|
||||||
newCount++;
|
newCount++;
|
||||||
} else {
|
} else {
|
||||||
console.warn(`[OpenList Refresh] TMDB 搜索失败: ${folder.name}`);
|
|
||||||
// 记录失败的文件夹
|
// 记录失败的文件夹
|
||||||
metaInfo.folders[folder.name] = {
|
metaInfo.folders[folder.name] = {
|
||||||
tmdb_id: 0,
|
tmdb_id: 0,
|
||||||
@@ -266,34 +203,11 @@ async function performScan(
|
|||||||
metaInfo.last_refresh = Date.now();
|
metaInfo.last_refresh = Date.now();
|
||||||
|
|
||||||
const metainfoContent = JSON.stringify(metaInfo);
|
const metainfoContent = JSON.stringify(metaInfo);
|
||||||
console.log('[OpenList Refresh] 保存 metainfo 到数据库:', {
|
|
||||||
videoCount: Object.keys(metaInfo.folders).length,
|
|
||||||
contentLength: metainfoContent.length,
|
|
||||||
});
|
|
||||||
|
|
||||||
await db.setGlobalValue('video.metainfo', metainfoContent);
|
await db.setGlobalValue('video.metainfo', metainfoContent);
|
||||||
console.log('[OpenList Refresh] 保存成功');
|
|
||||||
|
|
||||||
// 验证保存:立即读取数据库
|
|
||||||
try {
|
|
||||||
console.log('[OpenList Refresh] 验证保存:读取数据库');
|
|
||||||
const verifyContent = await db.getGlobalValue('video.metainfo');
|
|
||||||
if (verifyContent) {
|
|
||||||
const verifyParsed = JSON.parse(verifyContent);
|
|
||||||
console.log('[OpenList Refresh] 验证解析成功:', {
|
|
||||||
hasfolders: !!verifyParsed.folders,
|
|
||||||
foldersType: typeof verifyParsed.folders,
|
|
||||||
videoCount: Object.keys(verifyParsed.folders || {}).length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (verifyError) {
|
|
||||||
console.error('[OpenList Refresh] 验证失败:', verifyError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. 更新缓存
|
// 5. 更新缓存
|
||||||
invalidateMetaInfoCache(rootPath);
|
invalidateMetaInfoCache(rootPath);
|
||||||
setCachedMetaInfo(rootPath, metaInfo);
|
setCachedMetaInfo(rootPath, metaInfo);
|
||||||
console.log('[OpenList Refresh] 缓存已更新');
|
|
||||||
|
|
||||||
// 6. 更新配置
|
// 6. 更新配置
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
@@ -305,15 +219,7 @@ async function performScan(
|
|||||||
completeScanTask(taskId, {
|
completeScanTask(taskId, {
|
||||||
total: folders.length,
|
total: folders.length,
|
||||||
new: newCount,
|
new: newCount,
|
||||||
existing: Object.keys(metaInfo.folders).length - newCount,
|
existing: 0,
|
||||||
errors: errorCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('[OpenList Refresh] 扫描完成:', {
|
|
||||||
taskId,
|
|
||||||
total: folders.length,
|
|
||||||
new: newCount,
|
|
||||||
existing: Object.keys(metaInfo.folders).length - newCount,
|
|
||||||
errors: errorCount,
|
errors: errorCount,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -174,7 +174,8 @@ export class OpenListClient {
|
|||||||
async listDirectory(
|
async listDirectory(
|
||||||
path: string,
|
path: string,
|
||||||
page = 1,
|
page = 1,
|
||||||
perPage = 100
|
perPage = 100,
|
||||||
|
refresh = false
|
||||||
): Promise<OpenListListResponse> {
|
): Promise<OpenListListResponse> {
|
||||||
const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/list`, {
|
const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/list`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -182,7 +183,7 @@ export class OpenListClient {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
path,
|
path,
|
||||||
password: '',
|
password: '',
|
||||||
refresh: false,
|
refresh,
|
||||||
page,
|
page,
|
||||||
per_page: perPage,
|
per_page: perPage,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user