私人影库支持解析ova

This commit is contained in:
mtvpls
2026-01-03 16:40:39 +08:00
parent 2054e3122f
commit a10bf361a8
8 changed files with 62 additions and 23 deletions

View File

@@ -121,6 +121,7 @@ export async function GET(request: NextRequest) {
season: parsed.season,
title: parsed.title,
parsed_from: 'filename',
isOVA: parsed.isOVA,
};
}
setCachedVideoInfo(folderPath, videoInfo);
@@ -131,20 +132,26 @@ export async function GET(request: NextRequest) {
const parsed = parseVideoFileName(file.name);
let episodeInfo;
if (parsed.episode) {
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename' };
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename', isOVA: parsed.isOVA };
} else {
episodeInfo = videoInfo!.episodes[file.name] || { episode: index + 1, season: undefined, title: undefined, parsed_from: 'filename' };
}
let displayTitle = episodeInfo.title;
if (!displayTitle && episodeInfo.episode) {
displayTitle = `${episodeInfo.episode}`;
displayTitle = episodeInfo.isOVA ? `OVA ${episodeInfo.episode}` : `${episodeInfo.episode}`;
}
if (!displayTitle) {
displayTitle = file.name;
}
return { fileName: file.name, episode: episodeInfo.episode || 0, season: episodeInfo.season, title: displayTitle };
return { fileName: file.name, episode: episodeInfo.episode || 0, season: episodeInfo.season, title: displayTitle, isOVA: episodeInfo.isOVA };
})
.sort((a, b) => a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName));
.sort((a, b) => {
// OVA 排在最后
if (a.isOVA && !b.isOVA) return 1;
if (!a.isOVA && b.isOVA) return -1;
// 都是 OVA 或都不是 OVA按集数排序
return a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName);
});
// 3. 从 metainfo 中获取元数据
const { getTMDBImageUrl } = await import('@/lib/tmdb.search');

View File

@@ -315,6 +315,7 @@ async function handleDetail(
season: parsed.season,
title: parsed.title,
parsed_from: 'filename',
isOVA: parsed.isOVA,
};
}
setCachedVideoInfo(folderPath, videoInfo);
@@ -332,13 +333,13 @@ async function handleDetail(
const parsed = parseVideoFileName(file.name);
let episodeInfo;
if (parsed.episode) {
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename' };
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename', isOVA: parsed.isOVA };
} else {
episodeInfo = videoInfo!.episodes[file.name] || { episode: index + 1, season: undefined, title: undefined, parsed_from: 'filename' };
}
let displayTitle = episodeInfo.title;
if (!displayTitle && episodeInfo.episode) {
displayTitle = `${episodeInfo.episode}`;
displayTitle = episodeInfo.isOVA ? `OVA ${episodeInfo.episode}` : `${episodeInfo.episode}`;
}
if (!displayTitle) {
displayTitle = file.name;
@@ -353,9 +354,16 @@ async function handleDetail(
season: episodeInfo.season,
title: displayTitle,
playUrl,
isOVA: episodeInfo.isOVA,
};
})
.sort((a, b) => a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName));
.sort((a, b) => {
// OVA 排在最后
if (a.isOVA && !b.isOVA) return 1;
if (!a.isOVA && b.isOVA) return -1;
// 都是 OVA 或都不是 OVA按集数排序
return a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName);
});
// 转换为 CMS vod_play_url 格式
// 格式第1集$url1#第2集$url2#第3集$url3

View File

@@ -127,6 +127,7 @@ export async function GET(request: NextRequest) {
season: parsed.season,
title: parsed.title,
parsed_from: 'filename',
isOVA: parsed.isOVA,
};
}
@@ -174,6 +175,7 @@ export async function GET(request: NextRequest) {
season: parsed.season,
title: parsed.title,
parsed_from: 'filename',
isOVA: parsed.isOVA,
};
} else {
// 如果解析失败,尝试从 videoInfo 获取
@@ -192,8 +194,7 @@ export async function GET(request: NextRequest) {
// 优先使用解析出的标题,其次是"第X集"格式,最后才是文件名
let displayTitle = episodeInfo.title;
if (!displayTitle && episodeInfo.episode) {
// 支持小数集数显示
displayTitle = `${episodeInfo.episode}`;
displayTitle = episodeInfo.isOVA ? `OVA ${episodeInfo.episode}` : `${episodeInfo.episode}`;
}
if (!displayTitle) {
displayTitle = file.name;
@@ -205,9 +206,13 @@ export async function GET(request: NextRequest) {
season: episodeInfo.season,
title: displayTitle,
size: file.size,
isOVA: episodeInfo.isOVA,
};
})
.sort((a, b) => {
// OVA 排在最后
if (a.isOVA && !b.isOVA) return 1;
if (!a.isOVA && b.isOVA) return -1;
// 确保排序稳定,即使 episode 相同也按文件名排序
if (a.episode !== b.episode) {
return a.episode - b.episode;

View File

@@ -214,6 +214,7 @@ export async function GET(request: NextRequest) {
season: parsed.season,
title: parsed.title,
parsed_from: 'filename',
isOVA: parsed.isOVA,
};
}
setCachedVideoInfo(folderPath, videoInfo);
@@ -224,20 +225,26 @@ export async function GET(request: NextRequest) {
const parsed = parseVideoFileName(file.name);
let episodeInfo;
if (parsed.episode) {
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename' };
episodeInfo = { episode: parsed.episode, season: parsed.season, title: parsed.title, parsed_from: 'filename', isOVA: parsed.isOVA };
} else {
episodeInfo = videoInfo!.episodes[file.name] || { episode: index + 1, season: undefined, title: undefined, parsed_from: 'filename' };
}
let displayTitle = episodeInfo.title;
if (!displayTitle && episodeInfo.episode) {
displayTitle = `${episodeInfo.episode}`;
displayTitle = episodeInfo.isOVA ? `OVA ${episodeInfo.episode}` : `${episodeInfo.episode}`;
}
if (!displayTitle) {
displayTitle = file.name;
}
return { fileName: file.name, episode: episodeInfo.episode || 0, season: episodeInfo.season, title: displayTitle };
return { fileName: file.name, episode: episodeInfo.episode || 0, season: episodeInfo.season, title: displayTitle, isOVA: episodeInfo.isOVA };
})
.sort((a, b) => a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName));
.sort((a, b) => {
// OVA 排在最后
if (a.isOVA && !b.isOVA) return 1;
if (!a.isOVA && b.isOVA) return -1;
// 都是 OVA 或都不是 OVA按集数排序
return a.episode !== b.episode ? a.episode - b.episode : a.fileName.localeCompare(b.fileName);
});
// 3. 从 metainfo 中获取元数据
const { getTMDBImageUrl } = await import('@/lib/tmdb.search');