2025-12-22 00:42:27 +08:00
|
|
|
// metainfo.json 缓存 (7天)
|
|
|
|
|
interface MetaInfoCacheEntry {
|
|
|
|
|
expiresAt: number;
|
|
|
|
|
data: MetaInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// videoinfo.json 缓存 (1天)
|
|
|
|
|
interface VideoInfoCacheEntry {
|
|
|
|
|
expiresAt: number;
|
|
|
|
|
data: VideoInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const METAINFO_CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7天
|
2025-12-23 10:29:10 +08:00
|
|
|
const VIDEOINFO_CACHE_TTL_MS = (parseInt(process.env.VIDEOINFO_CACHE_MINUTES || '1440', 10)) * 60 * 1000; // 默认1天
|
2025-12-22 00:42:27 +08:00
|
|
|
|
|
|
|
|
const METAINFO_CACHE: Map<string, MetaInfoCacheEntry> = new Map();
|
|
|
|
|
const VIDEOINFO_CACHE: Map<string, VideoInfoCacheEntry> = new Map();
|
|
|
|
|
|
|
|
|
|
export interface MetaInfo {
|
|
|
|
|
folders: {
|
2025-12-26 21:13:12 +08:00
|
|
|
[key: string]: {
|
|
|
|
|
folderName: string; // 原始文件夹名称
|
2025-12-22 00:42:27 +08:00
|
|
|
tmdb_id: number;
|
|
|
|
|
title: string;
|
|
|
|
|
poster_path: string | null;
|
|
|
|
|
release_date: string;
|
|
|
|
|
overview: string;
|
|
|
|
|
vote_average: number;
|
|
|
|
|
media_type: 'movie' | 'tv';
|
|
|
|
|
last_updated: number;
|
2025-12-22 01:28:56 +08:00
|
|
|
failed?: boolean; // 标记是否搜索失败
|
2025-12-25 23:34:54 +08:00
|
|
|
season_number?: number; // 季度编号(仅电视剧)
|
|
|
|
|
season_name?: string; // 季度名称(仅电视剧)
|
2025-12-22 00:42:27 +08:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
last_refresh: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface VideoInfo {
|
|
|
|
|
episodes: {
|
|
|
|
|
[fileName: string]: {
|
|
|
|
|
episode: number;
|
|
|
|
|
season?: number;
|
|
|
|
|
title?: string;
|
|
|
|
|
parsed_from: 'videoinfo' | 'filename';
|
2026-01-03 16:40:39 +08:00
|
|
|
isOVA?: boolean;
|
2025-12-22 00:42:27 +08:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
last_updated: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MetaInfo 缓存操作
|
|
|
|
|
export function getCachedMetaInfo(rootPath: string): MetaInfo | null {
|
|
|
|
|
const entry = METAINFO_CACHE.get(rootPath);
|
|
|
|
|
if (!entry) return null;
|
|
|
|
|
|
|
|
|
|
if (entry.expiresAt <= Date.now()) {
|
|
|
|
|
METAINFO_CACHE.delete(rootPath);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return entry.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function setCachedMetaInfo(rootPath: string, data: MetaInfo): void {
|
|
|
|
|
METAINFO_CACHE.set(rootPath, {
|
|
|
|
|
expiresAt: Date.now() + METAINFO_CACHE_TTL_MS,
|
|
|
|
|
data,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function invalidateMetaInfoCache(rootPath: string): void {
|
|
|
|
|
METAINFO_CACHE.delete(rootPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VideoInfo 缓存操作
|
|
|
|
|
export function getCachedVideoInfo(folderPath: string): VideoInfo | null {
|
|
|
|
|
const entry = VIDEOINFO_CACHE.get(folderPath);
|
|
|
|
|
if (!entry) return null;
|
|
|
|
|
|
|
|
|
|
if (entry.expiresAt <= Date.now()) {
|
|
|
|
|
VIDEOINFO_CACHE.delete(folderPath);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return entry.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function setCachedVideoInfo(
|
|
|
|
|
folderPath: string,
|
|
|
|
|
data: VideoInfo
|
|
|
|
|
): void {
|
|
|
|
|
VIDEOINFO_CACHE.set(folderPath, {
|
|
|
|
|
expiresAt: Date.now() + VIDEOINFO_CACHE_TTL_MS,
|
|
|
|
|
data,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function invalidateVideoInfoCache(folderPath: string): void {
|
|
|
|
|
VIDEOINFO_CACHE.delete(folderPath);
|
|
|
|
|
}
|