From 44858b503a2e1b2ae484ef216a2375ca69272c71 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Mon, 8 Dec 2025 20:11:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=82=E5=BD=B1=E5=AE=A4=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BB=85=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 80 ++-------- src/app/admin/page.tsx | 211 -------------------------- src/app/api/admin/watch-room/route.ts | 98 ------------ src/app/api/server-config/route.ts | 25 ++- src/lib/admin.types.ts | 6 - 5 files changed, 19 insertions(+), 401 deletions(-) delete mode 100644 src/app/api/admin/watch-room/route.ts diff --git a/server.js b/server.js index e09fdab..f8d72c2 100644 --- a/server.js +++ b/server.js @@ -13,78 +13,16 @@ const handle = app.getRequestHandler(); // 读取观影室配置的辅助函数 async function getWatchRoomConfig() { - const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage'; + // 观影室配置现在统一从环境变量读取 + const config = { + enabled: process.env.WATCH_ROOM_ENABLED === 'true', + serverType: (process.env.WATCH_ROOM_SERVER_TYPE || 'internal'), + externalServerUrl: process.env.WATCH_ROOM_EXTERNAL_SERVER_URL, + externalServerAuth: process.env.WATCH_ROOM_EXTERNAL_SERVER_AUTH, + }; - // 如果使用 localStorage,无法在服务器端读取,返回默认配置(不启用) - if (storageType === 'localstorage') { - console.log('[WatchRoom] Using localStorage storage type.'); - // 在 localStorage 模式下,可以通过环境变量控制是否启用观影室 - const enabled = process.env.WATCH_ROOM_ENABLED === 'true'; - console.log(`[WatchRoom] Watch room ${enabled ? 'enabled' : 'disabled'} via environment variable.`); - return { enabled, serverType: 'internal' }; - } - - try { - if (storageType === 'redis') { - // 检查 Redis 配置 - const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; - console.log('[WatchRoom] Attempting to read config from Redis...'); - - const { createClient } = require('redis'); - const client = createClient({ url: redisUrl }); - await client.connect(); - - const configStr = await client.get('admin:config'); // 注意:使用冒号而不是下划线 - await client.disconnect(); - - if (configStr) { - const config = JSON.parse(configStr); - return config.WatchRoomConfig || { enabled: false, serverType: 'internal' }; - } - } else if (storageType === 'upstash') { - // 检查 Upstash 环境变量 - if (!process.env.UPSTASH_REDIS_REST_URL || !process.env.UPSTASH_REDIS_REST_TOKEN) { - console.log('[WatchRoom] Upstash credentials not configured. Socket.IO disabled by default.'); - return { enabled: false, serverType: 'internal' }; - } - - console.log('[WatchRoom] Attempting to read config from Upstash...'); - const { Redis } = require('@upstash/redis'); - const redis = new Redis({ - url: process.env.UPSTASH_REDIS_REST_URL, - token: process.env.UPSTASH_REDIS_REST_TOKEN, - }); - - const configStr = await redis.get('admin:config'); // 注意:使用冒号而不是下划线 - - if (configStr) { - const config = typeof configStr === 'string' ? JSON.parse(configStr) : configStr; - return config.WatchRoomConfig || { enabled: false, serverType: 'internal' }; - } - } else if (storageType === 'kvrocks') { - // 检查 Kvrocks 配置 - const kvrocksUrl = process.env.KVROCKS_URL || 'redis://localhost:6666'; - console.log('[WatchRoom] Attempting to read config from Kvrocks...'); - - const { createClient } = require('redis'); - const client = createClient({ url: kvrocksUrl }); - await client.connect(); - - const configStr = await client.get('admin:config'); // 注意:使用冒号而不是下划线 - await client.disconnect(); - - if (configStr) { - const config = JSON.parse(configStr); - return config.WatchRoomConfig || { enabled: false, serverType: 'internal' }; - } - } - } catch (error) { - console.error('[WatchRoom] Failed to read config from storage:', error.message); - } - - // 默认不启用观影室 - console.log('[WatchRoom] No config found or error occurred. Socket.IO disabled by default.'); - return { enabled: false, serverType: 'internal' }; + console.log(`[WatchRoom] Watch room ${config.enabled ? 'enabled' : 'disabled'} via environment variable.`); + return config; } // 观影室服务器类 diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 8e145df..03bc9db 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -5852,204 +5852,6 @@ const LiveSourceConfig = ({ ); }; -// 观影室配置组件 -const WatchRoomConfig = ({ - config, - refreshConfig, -}: { - config: AdminConfig | null; - refreshConfig: () => Promise; -}) => { - const { alertModal, showAlert, hideAlert } = useAlertModal(); - const { isLoading, withLoading } = useLoadingState(); - const [settings, setSettings] = useState({ - enabled: false, - serverType: 'internal' as 'internal' | 'external', - externalServerUrl: '', - externalServerAuth: '', - }); - - useEffect(() => { - if (config?.WatchRoomConfig) { - setSettings({ - enabled: config.WatchRoomConfig.enabled || false, - serverType: config.WatchRoomConfig.serverType || 'internal', - externalServerUrl: config.WatchRoomConfig.externalServerUrl || '', - externalServerAuth: config.WatchRoomConfig.externalServerAuth || '', - }); - } - }, [config]); - - const handleSave = async () => { - await withLoading('saveWatchRoomConfig', async () => { - try { - // 验证外部服务器配置 - if (settings.serverType === 'external' && !settings.externalServerUrl.trim()) { - showError('外部服务器地址不能为空', showAlert); - return; - } - - const resp = await fetch('/api/admin/watch-room', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(settings), - }); - - if (!resp.ok) { - const data = await resp.json().catch(() => ({})); - throw new Error(data.error || `保存失败: ${resp.status}`); - } - - showSuccess('保存成功,刷新页面后生效', showAlert); - await refreshConfig(); - } catch (err) { - showError(err instanceof Error ? err.message : '保存失败', showAlert); - throw err; - } - }); - }; - - if (!config) { - return ( -
- 加载中... -
- ); - } - - return ( -
- {/* 功能开关 */} -
-
-

- 启用观影室功能 -

-

- 开启后,用户可以创建和加入观影室,实现多人同步观看 -

-
- -
- - {/* 服务器类型选择 */} -
- - -

- {settings.serverType === 'internal' - ? '使用内置的 Socket.IO 服务器,无需额外配置' - : '使用独立部署的 Socket.IO 服务器,适合高并发场景'} -

-
- - {/* 外部服务器配置 */} - {settings.serverType === 'external' && ( -
-
- - - setSettings({ ...settings, externalServerUrl: e.target.value }) - } - placeholder='http://your-server:3001' - className='w-full px-3 py-2 text-sm text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent' - /> -

- 外部 Socket.IO 服务器的完整地址(包含协议和端口) -

-
- -
- - - setSettings({ ...settings, externalServerAuth: e.target.value }) - } - placeholder='可选:服务器鉴权密钥' - className='w-full px-3 py-2 text-sm text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent' - /> -

- 如果外部服务器需要鉴权,请填写密钥 -

-
-
- )} - - {/* 使用说明 */} -
-
- 使用说明 -
-
    -
  • 观影室功能允许多人同步观看视频,支持播放控制同步和聊天
  • -
  • 内部服务器模式无需额外配置,适合中小型部署
  • -
  • 外部服务器模式需要单独部署 Socket.IO 服务器(参考 server/watch-room-standalone-server.js)
  • -
  • 更改配置后需要重启服务器才能生效
  • -
-
- - {/* 保存按钮 */} -
- -
- - {/* 通用弹窗组件 */} - -
- ); -}; - function AdminPageClient() { const { alertModal, showAlert, hideAlert } = useAlertModal(); const { isLoading, withLoading } = useLoadingState(); @@ -6067,7 +5869,6 @@ function AdminPageClient() { configFile: false, dataMigration: false, customAdFilter: false, - watchRoomConfig: false, }); // 获取管理员配置 @@ -6256,18 +6057,6 @@ function AdminPageClient() { - {/* 观影室配置标签 */} - - } - isExpanded={expandedTabs.watchRoomConfig} - onToggle={() => toggleTab('watchRoomConfig')} - > - - - {/* 分类配置标签 */} u.username === username - ); - if (!user || user.role !== 'admin' || user.banned) { - return NextResponse.json({ error: '权限不足' }, { status: 401 }); - } - } - - // 更新缓存中的观影室配置 - adminConfig.WatchRoomConfig = { - enabled, - serverType, - externalServerUrl, - externalServerAuth, - }; - - // 写入数据库 - await db.saveAdminConfig(adminConfig); - - return NextResponse.json( - { ok: true }, - { - headers: { - 'Cache-Control': 'no-store', // 不缓存结果 - }, - } - ); - } catch (error) { - console.error('更新观影室配置失败:', error); - return NextResponse.json( - { - error: '更新观影室配置失败', - details: (error as Error).message, - }, - { status: 500 } - ); - } -} diff --git a/src/app/api/server-config/route.ts b/src/app/api/server-config/route.ts index 6c7ac24..50401f2 100644 --- a/src/app/api/server-config/route.ts +++ b/src/app/api/server-config/route.ts @@ -12,20 +12,21 @@ export async function GET(request: NextRequest) { const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage'; + // 观影室配置从环境变量读取 + const watchRoomConfig = { + enabled: process.env.WATCH_ROOM_ENABLED === 'true', + serverType: (process.env.WATCH_ROOM_SERVER_TYPE as 'internal' | 'external') || 'internal', + externalServerUrl: process.env.WATCH_ROOM_EXTERNAL_SERVER_URL, + externalServerAuth: process.env.WATCH_ROOM_EXTERNAL_SERVER_AUTH, + }; + // 如果使用 localStorage,返回默认配置 if (storageType === 'localstorage') { return NextResponse.json({ SiteName: process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV', StorageType: 'localstorage', Version: CURRENT_VERSION, - // localStorage 模式下,返回默认观影室配置 - // 可以通过环境变量控制是否启用 - WatchRoom: { - enabled: process.env.WATCH_ROOM_ENABLED === 'true', - serverType: 'internal', - externalServerUrl: undefined, - externalServerAuth: undefined, - }, + WatchRoom: watchRoomConfig, }); } @@ -35,13 +36,7 @@ export async function GET(request: NextRequest) { SiteName: config.SiteConfig.SiteName, StorageType: storageType, Version: CURRENT_VERSION, - // 添加观影室配置(供所有用户访问) - WatchRoom: { - enabled: config.WatchRoomConfig?.enabled ?? false, - serverType: config.WatchRoomConfig?.serverType ?? 'internal', - externalServerUrl: config.WatchRoomConfig?.externalServerUrl, - externalServerAuth: config.WatchRoomConfig?.externalServerAuth, - }, + WatchRoom: watchRoomConfig, }; return NextResponse.json(result); } diff --git a/src/lib/admin.types.ts b/src/lib/admin.types.ts index b280d02..8f6c30a 100644 --- a/src/lib/admin.types.ts +++ b/src/lib/admin.types.ts @@ -63,12 +63,6 @@ export interface AdminConfig { channelNumber?: number; disabled?: boolean; }[]; - WatchRoomConfig?: { - enabled: boolean; - serverType: 'internal' | 'external'; - externalServerUrl?: string; - externalServerAuth?: string; - }; } export interface AdminConfigResult {