openlist多目录支持
This commit is contained in:
@@ -2763,7 +2763,7 @@ const OpenListConfigComponent = ({
|
||||
const [url, setUrl] = useState('');
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [rootPath, setRootPath] = useState('/');
|
||||
const [rootPaths, setRootPaths] = useState<string[]>(['/']);
|
||||
const [offlineDownloadPath, setOfflineDownloadPath] = useState('/');
|
||||
const [scanInterval, setScanInterval] = useState(0);
|
||||
const [scanMode, setScanMode] = useState<'torrent' | 'name' | 'hybrid'>('hybrid');
|
||||
@@ -2783,7 +2783,7 @@ const OpenListConfigComponent = ({
|
||||
setUrl(config.OpenListConfig.URL || '');
|
||||
setUsername(config.OpenListConfig.Username || '');
|
||||
setPassword(config.OpenListConfig.Password || '');
|
||||
setRootPath(config.OpenListConfig.RootPath || '/');
|
||||
setRootPaths(config.OpenListConfig.RootPaths || (config.OpenListConfig.RootPath ? [config.OpenListConfig.RootPath] : ['/']));
|
||||
setOfflineDownloadPath(config.OpenListConfig.OfflineDownloadPath || '/');
|
||||
setScanInterval(config.OpenListConfig.ScanInterval || 0);
|
||||
setScanMode(config.OpenListConfig.ScanMode || 'hybrid');
|
||||
@@ -2824,7 +2824,7 @@ const OpenListConfigComponent = ({
|
||||
URL: url,
|
||||
Username: username,
|
||||
Password: password,
|
||||
RootPath: rootPath,
|
||||
RootPaths: rootPaths,
|
||||
OfflineDownloadPath: offlineDownloadPath,
|
||||
ScanInterval: scanInterval,
|
||||
ScanMode: scanMode,
|
||||
@@ -3104,18 +3104,49 @@ const OpenListConfigComponent = ({
|
||||
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||
根目录
|
||||
根目录列表
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={rootPath}
|
||||
onChange={(e) => setRootPath(e.target.value)}
|
||||
disabled={!enabled}
|
||||
placeholder='/'
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
/>
|
||||
<div className='space-y-2'>
|
||||
{rootPaths.map((path, index) => (
|
||||
<div key={index} className='flex gap-2'>
|
||||
<input
|
||||
type='text'
|
||||
value={path}
|
||||
onChange={(e) => {
|
||||
const newPaths = [...rootPaths];
|
||||
newPaths[index] = e.target.value;
|
||||
setRootPaths(newPaths);
|
||||
}}
|
||||
disabled={!enabled}
|
||||
placeholder='/'
|
||||
className='flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
/>
|
||||
{rootPaths.length > 1 && (
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
const newPaths = rootPaths.filter((_, i) => i !== index);
|
||||
setRootPaths(newPaths);
|
||||
}}
|
||||
disabled={!enabled}
|
||||
className='px-3 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
>
|
||||
删除
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setRootPaths([...rootPaths, '/'])}
|
||||
disabled={!enabled}
|
||||
className='w-full px-3 py-2 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg text-gray-600 dark:text-gray-400 hover:border-blue-500 hover:text-blue-500 disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
>
|
||||
+ 添加根目录
|
||||
</button>
|
||||
</div>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
OpenList 中的视频文件夹路径,默认为根目录 /
|
||||
OpenList 中的视频文件夹路径,可以配置多个根目录
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { action, Enabled, URL, Username, Password, RootPath, OfflineDownloadPath, ScanInterval, ScanMode } = body;
|
||||
const { action, Enabled, URL, Username, Password, RootPaths, OfflineDownloadPath, ScanInterval, ScanMode } = body;
|
||||
|
||||
const authInfo = getAuthInfoFromCookie(request);
|
||||
if (!authInfo || !authInfo.username) {
|
||||
@@ -53,7 +53,7 @@ export async function POST(request: NextRequest) {
|
||||
URL: URL || '',
|
||||
Username: Username || '',
|
||||
Password: Password || '',
|
||||
RootPath: RootPath || '/',
|
||||
RootPaths: RootPaths || ['/'],
|
||||
OfflineDownloadPath: OfflineDownloadPath || '/',
|
||||
LastRefreshTime: adminConfig.OpenListConfig?.LastRefreshTime,
|
||||
ResourceCount: adminConfig.OpenListConfig?.ResourceCount,
|
||||
@@ -77,6 +77,14 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// 验证 RootPaths
|
||||
if (!Array.isArray(RootPaths) || RootPaths.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ error: '请至少提供一个根目录' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 验证扫描间隔
|
||||
let scanInterval = parseInt(ScanInterval) || 0;
|
||||
if (scanInterval > 0 && scanInterval < 60) {
|
||||
@@ -104,7 +112,7 @@ export async function POST(request: NextRequest) {
|
||||
URL,
|
||||
Username,
|
||||
Password,
|
||||
RootPath: RootPath || '/',
|
||||
RootPaths,
|
||||
OfflineDownloadPath: OfflineDownloadPath || '/',
|
||||
LastRefreshTime: adminConfig.OpenListConfig?.LastRefreshTime,
|
||||
ResourceCount: adminConfig.OpenListConfig?.ResourceCount,
|
||||
|
||||
@@ -268,14 +268,14 @@ async function handleOpenListProxy(request: NextRequest) {
|
||||
);
|
||||
|
||||
// 读取 metainfo (从数据库或缓存)
|
||||
let metaInfo: MetaInfo | null = getCachedMetaInfo(rootPath);
|
||||
let metaInfo: MetaInfo | null = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
try {
|
||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson) as MetaInfo;
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -45,13 +45,13 @@ export async function GET(request: NextRequest) {
|
||||
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
|
||||
const { db } = await import('@/lib/db');
|
||||
|
||||
metaInfo = getCachedMetaInfo(rootPath);
|
||||
metaInfo = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson);
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function GET(
|
||||
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
|
||||
const { db } = await import('@/lib/db');
|
||||
|
||||
let metaInfo = getCachedMetaInfo(rootPath);
|
||||
let metaInfo = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
try {
|
||||
@@ -84,7 +84,7 @@ export async function GET(
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson);
|
||||
if (metaInfo) {
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -65,7 +65,6 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
const client = new OpenListClient(
|
||||
openListConfig.URL,
|
||||
openListConfig.Username,
|
||||
@@ -73,7 +72,7 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
|
||||
// 读取现有 metainfo (从数据库或缓存)
|
||||
let metaInfo: MetaInfo | null = getCachedMetaInfo(rootPath);
|
||||
let metaInfo: MetaInfo | null = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
try {
|
||||
@@ -132,8 +131,8 @@ export async function POST(request: NextRequest) {
|
||||
await db.setGlobalValue('video.metainfo', metainfoContent);
|
||||
|
||||
// 更新缓存
|
||||
invalidateMetaInfoCache(rootPath);
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
invalidateMetaInfoCache();
|
||||
setCachedMetaInfo(metaInfo);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
|
||||
@@ -49,8 +49,6 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
|
||||
// 从数据库读取 metainfo
|
||||
const metainfoContent = await db.getGlobalValue('video.metainfo');
|
||||
if (!metainfoContent) {
|
||||
@@ -78,8 +76,8 @@ export async function POST(request: NextRequest) {
|
||||
await db.setGlobalValue('video.metainfo', updatedMetainfoContent);
|
||||
|
||||
// 更新缓存
|
||||
invalidateMetaInfoCache(rootPath);
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
invalidateMetaInfoCache();
|
||||
setCachedMetaInfo(metaInfo);
|
||||
|
||||
// 更新配置中的资源数量
|
||||
if (config.OpenListConfig) {
|
||||
|
||||
@@ -45,8 +45,8 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'OpenList 未配置或未启用' }, { status: 400 });
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
const folderPath = `${rootPath}${rootPath.endsWith('/') ? '' : '/'}${folderName}`;
|
||||
// folderName 已经是完整路径,直接使用
|
||||
const folderPath = folderName;
|
||||
const client = new OpenListClient(
|
||||
openListConfig.URL,
|
||||
openListConfig.Username,
|
||||
|
||||
@@ -48,7 +48,6 @@ export async function GET(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
const client = new OpenListClient(
|
||||
openListConfig.URL,
|
||||
openListConfig.Username,
|
||||
@@ -62,7 +61,7 @@ export async function GET(request: NextRequest) {
|
||||
if (noCache) {
|
||||
// noCache 模式:跳过缓存
|
||||
} else {
|
||||
metaInfo = getCachedMetaInfo(rootPath);
|
||||
metaInfo = getCachedMetaInfo();
|
||||
}
|
||||
|
||||
if (!metaInfo) {
|
||||
@@ -83,7 +82,7 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
// 只有在不是 noCache 模式时才更新缓存
|
||||
if (!noCache) {
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('[OpenList List] JSON 解析或验证失败:', parseError);
|
||||
|
||||
@@ -41,8 +41,8 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'OpenList 未配置或未启用' }, { status: 400 });
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
const folderPath = `${rootPath}${rootPath.endsWith('/') ? '' : '/'}${folderName}`;
|
||||
// folderName 已经是完整路径,直接使用
|
||||
const folderPath = folderName;
|
||||
const filePath = `${folderPath}/${fileName}`;
|
||||
|
||||
const client = new OpenListClient(
|
||||
|
||||
@@ -40,8 +40,8 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'OpenList 未配置或未启用' }, { status: 400 });
|
||||
}
|
||||
|
||||
const rootPath = openListConfig.RootPath || '/';
|
||||
const folderPath = `${rootPath}${rootPath.endsWith('/') ? '' : '/'}${folder}`;
|
||||
// folder 已经是完整路径,直接使用
|
||||
const folderPath = folder;
|
||||
const client = new OpenListClient(
|
||||
openListConfig.URL,
|
||||
openListConfig.Username,
|
||||
|
||||
@@ -105,15 +105,14 @@ export async function GET(request: NextRequest) {
|
||||
const { getTMDBImageUrl } = await import('@/lib/tmdb.search');
|
||||
const { db } = await import('@/lib/db');
|
||||
|
||||
const rootPath = config.OpenListConfig!.RootPath || '/';
|
||||
let metaInfo = getCachedMetaInfo(rootPath);
|
||||
let metaInfo = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson);
|
||||
if (metaInfo) {
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,15 +213,14 @@ export async function GET(request: NextRequest) {
|
||||
const { getTMDBImageUrl } = await import('@/lib/tmdb.search');
|
||||
const { db } = await import('@/lib/db');
|
||||
|
||||
const rootPath = config.OpenListConfig!.RootPath || '/';
|
||||
let metaInfo = getCachedMetaInfo(rootPath);
|
||||
let metaInfo = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson);
|
||||
if (metaInfo) {
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,13 +149,13 @@ export async function GET(request: NextRequest) {
|
||||
const { getCachedMetaInfo, setCachedMetaInfo } = await import('@/lib/openlist-cache');
|
||||
const { db } = await import('@/lib/db');
|
||||
|
||||
metaInfo = getCachedMetaInfo(rootPath);
|
||||
metaInfo = getCachedMetaInfo();
|
||||
|
||||
if (!metaInfo) {
|
||||
const metainfoJson = await db.getGlobalValue('video.metainfo');
|
||||
if (metainfoJson) {
|
||||
metaInfo = JSON.parse(metainfoJson);
|
||||
setCachedMetaInfo(rootPath, metaInfo);
|
||||
setCachedMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user