私人影库增加开关
This commit is contained in:
@@ -2540,6 +2540,7 @@ const OpenListConfigComponent = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { alertModal, showAlert, hideAlert } = useAlertModal();
|
const { alertModal, showAlert, hideAlert } = useAlertModal();
|
||||||
const { isLoading, withLoading } = useLoadingState();
|
const { isLoading, withLoading } = useLoadingState();
|
||||||
|
const [enabled, setEnabled] = useState(false);
|
||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
@@ -2557,6 +2558,7 @@ const OpenListConfigComponent = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (config?.OpenListConfig) {
|
if (config?.OpenListConfig) {
|
||||||
|
setEnabled(config.OpenListConfig.Enabled || false);
|
||||||
setUrl(config.OpenListConfig.URL || '');
|
setUrl(config.OpenListConfig.URL || '');
|
||||||
setUsername(config.OpenListConfig.Username || '');
|
setUsername(config.OpenListConfig.Username || '');
|
||||||
setPassword(config.OpenListConfig.Password || '');
|
setPassword(config.OpenListConfig.Password || '');
|
||||||
@@ -2595,6 +2597,7 @@ const OpenListConfigComponent = ({
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: 'save',
|
action: 'save',
|
||||||
|
Enabled: enabled,
|
||||||
URL: url,
|
URL: url,
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
@@ -2719,6 +2722,57 @@ const OpenListConfigComponent = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='space-y-6'>
|
<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 className='space-y-4'>
|
||||||
<div>
|
<div>
|
||||||
@@ -2729,8 +2783,9 @@ const OpenListConfigComponent = ({
|
|||||||
type='text'
|
type='text'
|
||||||
value={url}
|
value={url}
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
|
disabled={!enabled}
|
||||||
placeholder='https://your-openlist-server.com'
|
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>
|
</div>
|
||||||
|
|
||||||
@@ -2743,8 +2798,9 @@ const OpenListConfigComponent = ({
|
|||||||
type='text'
|
type='text'
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
disabled={!enabled}
|
||||||
placeholder='admin'
|
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>
|
||||||
<div>
|
<div>
|
||||||
@@ -2755,8 +2811,9 @@ const OpenListConfigComponent = ({
|
|||||||
type='password'
|
type='password'
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
disabled={!enabled}
|
||||||
placeholder='password'
|
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>
|
||||||
</div>
|
</div>
|
||||||
@@ -2769,8 +2826,9 @@ const OpenListConfigComponent = ({
|
|||||||
type='text'
|
type='text'
|
||||||
value={rootPath}
|
value={rootPath}
|
||||||
onChange={(e) => setRootPath(e.target.value)}
|
onChange={(e) => setRootPath(e.target.value)}
|
||||||
|
disabled={!enabled}
|
||||||
placeholder='/'
|
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'>
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
OpenList 中的视频文件夹路径,默认为根目录 /
|
OpenList 中的视频文件夹路径,默认为根目录 /
|
||||||
@@ -2785,9 +2843,10 @@ const OpenListConfigComponent = ({
|
|||||||
type='number'
|
type='number'
|
||||||
value={scanInterval}
|
value={scanInterval}
|
||||||
onChange={(e) => setScanInterval(parseInt(e.target.value) || 0)}
|
onChange={(e) => setScanInterval(parseInt(e.target.value) || 0)}
|
||||||
|
disabled={!enabled}
|
||||||
placeholder='0'
|
placeholder='0'
|
||||||
min='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'>
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
设置为 0 关闭定时扫描,最低 60 分钟
|
设置为 0 关闭定时扫描,最低 60 分钟
|
||||||
@@ -2806,7 +2865,7 @@ const OpenListConfigComponent = ({
|
|||||||
</div>
|
</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='space-y-4'>
|
||||||
<div className='flex items-center justify-between'>
|
<div className='flex items-center justify-between'>
|
||||||
<div>
|
<div>
|
||||||
@@ -7675,18 +7734,6 @@ function AdminPageClient() {
|
|||||||
<VideoSourceConfig config={config} refreshConfig={fetchConfig} />
|
<VideoSourceConfig config={config} refreshConfig={fetchConfig} />
|
||||||
</CollapsibleTab>
|
</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
|
<CollapsibleTab
|
||||||
title='直播源配置'
|
title='直播源配置'
|
||||||
@@ -7699,6 +7746,18 @@ function AdminPageClient() {
|
|||||||
<LiveSourceConfig config={config} refreshConfig={fetchConfig} />
|
<LiveSourceConfig config={config} refreshConfig={fetchConfig} />
|
||||||
</CollapsibleTab>
|
</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
|
<CollapsibleTab
|
||||||
title='分类配置'
|
title='分类配置'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const body = await request.json();
|
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);
|
const authInfo = getAuthInfoFromCookie(request);
|
||||||
if (!authInfo || !authInfo.username) {
|
if (!authInfo || !authInfo.username) {
|
||||||
@@ -48,7 +48,28 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'save') {
|
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) {
|
if (!URL || !Username || !Password) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: '请提供 URL、账号和密码' },
|
{ error: '请提供 URL、账号和密码' },
|
||||||
@@ -79,6 +100,7 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
adminConfig.OpenListConfig = {
|
adminConfig.OpenListConfig = {
|
||||||
|
Enabled: true,
|
||||||
URL,
|
URL,
|
||||||
Username,
|
Username,
|
||||||
Password,
|
Password,
|
||||||
|
|||||||
@@ -292,8 +292,14 @@ async function refreshOpenList() {
|
|||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
const openListConfig = config.OpenListConfig;
|
const openListConfig = config.OpenListConfig;
|
||||||
|
|
||||||
|
// 检查功能是否启用
|
||||||
|
if (!openListConfig || !openListConfig.Enabled) {
|
||||||
|
console.log('跳过 OpenList 扫描:功能未启用');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否配置了 OpenList 和定时扫描
|
// 检查是否配置了 OpenList 和定时扫描
|
||||||
if (!openListConfig || !openListConfig.URL || !openListConfig.Username || !openListConfig.Password) {
|
if (!openListConfig.URL || !openListConfig.Username || !openListConfig.Password) {
|
||||||
console.log('跳过 OpenList 扫描:未配置');
|
console.log('跳过 OpenList 扫描:未配置');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,8 +88,9 @@ export default async function RootLayout({
|
|||||||
fluidSearch = config.SiteConfig.FluidSearch;
|
fluidSearch = config.SiteConfig.FluidSearch;
|
||||||
enableComments = config.SiteConfig.EnableComments;
|
enableComments = config.SiteConfig.EnableComments;
|
||||||
tmdbApiKey = config.SiteConfig.TMDBApiKey || '';
|
tmdbApiKey = config.SiteConfig.TMDBApiKey || '';
|
||||||
// 检查是否配置了 OpenList
|
// 检查是否启用了 OpenList 功能
|
||||||
openListEnabled = !!(
|
openListEnabled = !!(
|
||||||
|
config.OpenListConfig?.Enabled &&
|
||||||
config.OpenListConfig?.URL &&
|
config.OpenListConfig?.URL &&
|
||||||
config.OpenListConfig?.Username &&
|
config.OpenListConfig?.Username &&
|
||||||
config.OpenListConfig?.Password
|
config.OpenListConfig?.Password
|
||||||
|
|||||||
@@ -70,9 +70,14 @@ export default function PrivateLibraryPage() {
|
|||||||
return (
|
return (
|
||||||
<PageLayout activePath='/private-library'>
|
<PageLayout activePath='/private-library'>
|
||||||
<div className='container mx-auto px-4 py-6'>
|
<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>
|
私人影库
|
||||||
|
</h1>
|
||||||
|
<p className='text-sm text-gray-500 dark:text-gray-400 mt-1'>
|
||||||
|
观看自我收藏的高清视频吧
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{error && (
|
{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'>
|
<div className='bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 mb-6'>
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export interface AdminConfig {
|
|||||||
cacheVersion: number; // CSS版本号(用于缓存控制)
|
cacheVersion: number; // CSS版本号(用于缓存控制)
|
||||||
};
|
};
|
||||||
OpenListConfig?: {
|
OpenListConfig?: {
|
||||||
|
Enabled: boolean; // 是否启用私人影库功能
|
||||||
URL: string; // OpenList 服务器地址
|
URL: string; // OpenList 服务器地址
|
||||||
Username: string; // 账号(用于登录获取Token)
|
Username: string; // 账号(用于登录获取Token)
|
||||||
Password: string; // 密码(用于登录获取Token)
|
Password: string; // 密码(用于登录获取Token)
|
||||||
|
|||||||
Reference in New Issue
Block a user