私人影库增加开关

This commit is contained in:
mtvpls
2025-12-22 23:08:03 +08:00
parent 02a76f83ba
commit ac3e68ec10
6 changed files with 119 additions and 25 deletions

View File

@@ -2540,6 +2540,7 @@ const OpenListConfigComponent = ({
}) => {
const { alertModal, showAlert, hideAlert } = useAlertModal();
const { isLoading, withLoading } = useLoadingState();
const [enabled, setEnabled] = useState(false);
const [url, setUrl] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
@@ -2557,6 +2558,7 @@ const OpenListConfigComponent = ({
useEffect(() => {
if (config?.OpenListConfig) {
setEnabled(config.OpenListConfig.Enabled || false);
setUrl(config.OpenListConfig.URL || '');
setUsername(config.OpenListConfig.Username || '');
setPassword(config.OpenListConfig.Password || '');
@@ -2595,6 +2597,7 @@ const OpenListConfigComponent = ({
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'save',
Enabled: enabled,
URL: url,
Username: username,
Password: password,
@@ -2719,6 +2722,57 @@ const OpenListConfigComponent = ({
return (
<div className='space-y-6'>
{/* 使用说明 */}
<div className='bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4'>
<div className='flex items-center gap-2 mb-2'>
<svg
className='w-5 h-5 text-blue-600 dark:text-blue-400'
fill='none'
stroke='currentColor'
viewBox='0 0 24 24'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth={2}
d='M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'
/>
</svg>
<span className='text-sm font-medium text-blue-800 dark:text-blue-300'>
使
</span>
</div>
<div className='text-sm text-blue-700 dark:text-blue-400 space-y-1'>
<p> OpenList 使</p>
<p> OpenList OneDrive </p>
<p> TMDB </p>
<p> 0 60 </p>
<p> TMDB </p>
</div>
</div>
{/* 功能开关 */}
<div className='flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700'>
<div>
<h3 className='text-sm font-medium text-gray-900 dark:text-gray-100'>
</h3>
<p className='text-xs text-gray-500 dark:text-gray-400 mt-1'>
</p>
</div>
<label className='relative inline-flex items-center cursor-pointer'>
<input
type='checkbox'
checked={enabled}
onChange={(e) => setEnabled(e.target.checked)}
className='sr-only peer'
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
</label>
</div>
{/* 配置表单 */}
<div className='space-y-4'>
<div>
@@ -2729,8 +2783,9 @@ const OpenListConfigComponent = ({
type='text'
value={url}
onChange={(e) => setUrl(e.target.value)}
disabled={!enabled}
placeholder='https://your-openlist-server.com'
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'
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>
@@ -2743,8 +2798,9 @@ const OpenListConfigComponent = ({
type='text'
value={username}
onChange={(e) => setUsername(e.target.value)}
disabled={!enabled}
placeholder='admin'
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'
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>
<div>
@@ -2755,8 +2811,9 @@ const OpenListConfigComponent = ({
type='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={!enabled}
placeholder='password'
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'
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>
</div>
@@ -2769,8 +2826,9 @@ const OpenListConfigComponent = ({
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'
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'
/>
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
OpenList /
@@ -2785,9 +2843,10 @@ const OpenListConfigComponent = ({
type='number'
value={scanInterval}
onChange={(e) => setScanInterval(parseInt(e.target.value) || 0)}
disabled={!enabled}
placeholder='0'
min='0'
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'
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'
/>
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
0 60
@@ -2806,7 +2865,7 @@ const OpenListConfigComponent = ({
</div>
{/* 视频列表区域 */}
{config?.OpenListConfig?.URL && config?.OpenListConfig?.Username && config?.OpenListConfig?.Password && (
{enabled && config?.OpenListConfig?.URL && config?.OpenListConfig?.Username && config?.OpenListConfig?.Password && (
<div className='space-y-4'>
<div className='flex items-center justify-between'>
<div>
@@ -7675,18 +7734,6 @@ function AdminPageClient() {
<VideoSourceConfig config={config} refreshConfig={fetchConfig} />
</CollapsibleTab>
{/* 私人影库配置标签 */}
<CollapsibleTab
title='私人影库'
icon={
<FolderOpen size={20} className='text-gray-600 dark:text-gray-400' />
}
isExpanded={expandedTabs.openListConfig}
onToggle={() => toggleTab('openListConfig')}
>
<OpenListConfigComponent config={config} refreshConfig={fetchConfig} />
</CollapsibleTab>
{/* 直播源配置标签 */}
<CollapsibleTab
title='直播源配置'
@@ -7699,6 +7746,18 @@ function AdminPageClient() {
<LiveSourceConfig config={config} refreshConfig={fetchConfig} />
</CollapsibleTab>
{/* 私人影库配置标签 */}
<CollapsibleTab
title='私人影库'
icon={
<FolderOpen size={20} className='text-gray-600 dark:text-gray-400' />
}
isExpanded={expandedTabs.openListConfig}
onToggle={() => toggleTab('openListConfig')}
>
<OpenListConfigComponent config={config} refreshConfig={fetchConfig} />
</CollapsibleTab>
{/* 分类配置标签 */}
<CollapsibleTab
title='分类配置'

View File

@@ -26,7 +26,7 @@ export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { action, URL, Username, Password, RootPath, ScanInterval } = body;
const { action, Enabled, URL, Username, Password, RootPath, ScanInterval } = body;
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo || !authInfo.username) {
@@ -48,7 +48,28 @@ export async function POST(request: NextRequest) {
}
if (action === 'save') {
// 保存配置
// 如果功能未启用,允许保存配置
if (!Enabled) {
adminConfig.OpenListConfig = {
Enabled: false,
URL: URL || '',
Username: Username || '',
Password: Password || '',
RootPath: RootPath || '/',
LastRefreshTime: adminConfig.OpenListConfig?.LastRefreshTime,
ResourceCount: adminConfig.OpenListConfig?.ResourceCount,
ScanInterval: 0,
};
await db.saveAdminConfig(adminConfig);
return NextResponse.json({
success: true,
message: '保存成功',
});
}
// 功能启用时,验证必填字段
if (!URL || !Username || !Password) {
return NextResponse.json(
{ error: '请提供 URL、账号和密码' },
@@ -79,6 +100,7 @@ export async function POST(request: NextRequest) {
}
adminConfig.OpenListConfig = {
Enabled: true,
URL,
Username,
Password,

View File

@@ -292,8 +292,14 @@ async function refreshOpenList() {
const config = await getConfig();
const openListConfig = config.OpenListConfig;
// 检查功能是否启用
if (!openListConfig || !openListConfig.Enabled) {
console.log('跳过 OpenList 扫描:功能未启用');
return;
}
// 检查是否配置了 OpenList 和定时扫描
if (!openListConfig || !openListConfig.URL || !openListConfig.Username || !openListConfig.Password) {
if (!openListConfig.URL || !openListConfig.Username || !openListConfig.Password) {
console.log('跳过 OpenList 扫描:未配置');
return;
}

View File

@@ -88,8 +88,9 @@ export default async function RootLayout({
fluidSearch = config.SiteConfig.FluidSearch;
enableComments = config.SiteConfig.EnableComments;
tmdbApiKey = config.SiteConfig.TMDBApiKey || '';
// 检查是否配置了 OpenList
// 检查是否启用了 OpenList 功能
openListEnabled = !!(
config.OpenListConfig?.Enabled &&
config.OpenListConfig?.URL &&
config.OpenListConfig?.Username &&
config.OpenListConfig?.Password

View File

@@ -70,9 +70,14 @@ export default function PrivateLibraryPage() {
return (
<PageLayout activePath='/private-library'>
<div className='container mx-auto px-4 py-6'>
<h1 className='text-2xl font-bold text-gray-900 dark:text-gray-100 mb-6'>
<div className='mb-6'>
<h1 className='text-2xl font-bold text-gray-900 dark:text-gray-100'>
</h1>
<p className='text-sm text-gray-500 dark:text-gray-400 mt-1'>
</p>
</div>
{error && (
<div className='bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 mb-6'>

View File

@@ -92,6 +92,7 @@ export interface AdminConfig {
cacheVersion: number; // CSS版本号用于缓存控制
};
OpenListConfig?: {
Enabled: boolean; // 是否启用私人影库功能
URL: string; // OpenList 服务器地址
Username: string; // 账号用于登录获取Token
Password: string; // 密码用于登录获取Token