From 047691d1a530df7242415d407e1ee8d249da7485 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sat, 7 Mar 2026 10:19:38 +0800 Subject: [PATCH] =?UTF-8?q?emby=E6=94=AF=E6=8C=81=E6=97=A0=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/admin/page.tsx | 183 ++++++++++++++++++++++---------- src/app/api/admin/emby/route.ts | 8 +- src/lib/emby.client.ts | 6 +- 3 files changed, 136 insertions(+), 61 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 8a5b184..d6745d0 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -3514,6 +3514,7 @@ const EmbyConfigComponent = ({ proxyPlay: false, customUserAgent: '', }); + const [authMode, setAuthMode] = useState<'apikey' | 'password'>('apikey'); // 从配置加载源列表 useEffect(() => { @@ -3554,6 +3555,7 @@ const EmbyConfigComponent = ({ proxyPlay: false, customUserAgent: '', }); + setAuthMode('apikey'); setEditingSource(null); setShowAddForm(false); }; @@ -3561,6 +3563,14 @@ const EmbyConfigComponent = ({ // 开始编辑 const handleEdit = (source: any) => { setFormData({ ...source }); + // 根据现有配置判断认证方式 + if (source.ApiKey) { + setAuthMode('apikey'); + } else if (source.Username) { + setAuthMode('password'); + } else { + setAuthMode('apikey'); + } setEditingSource(source); setShowAddForm(false); }; @@ -3579,6 +3589,19 @@ const EmbyConfigComponent = ({ return; } + // 根据认证方式验证必填字段 + if (authMode === 'apikey') { + if (!formData.ApiKey || !formData.UserId) { + showError('使用密钥认证时,API Key 和用户 ID 为必填项', showAlert); + return; + } + } else if (authMode === 'password') { + if (!formData.Username) { + showError('使用账号认证时,用户名为必填项', showAlert); + return; + } + } + // 验证key唯一性 if (!editingSource && sources.some(s => s.key === formData.key)) { showError('标识符已存在,请使用其他标识符', showAlert); @@ -4088,67 +4111,119 @@ const EmbyConfigComponent = ({ /> - {/* API Key */} + {/* 认证方式切换卡 */}
- setFormData({ ...formData, ApiKey: e.target.value })} - placeholder='输入 Emby API Key' - 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' - /> -

- 推荐使用 API Key 认证。如果不使用 API Key,请填写下方的用户名和密码。 -

+
+ + +
- {/* 用户名 */} -
- - setFormData({ ...formData, Username: e.target.value })} - placeholder='Emby 用户名' - 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' - /> -
+ {/* 密钥认证模式 */} + {authMode === 'apikey' && ( + <> + {/* API Key */} +
+ + setFormData({ ...formData, ApiKey: e.target.value })} + placeholder='输入 Emby API Key' + 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' + /> +

+ 在 Emby 控制台的 API 密钥页面生成 +

+
- {/* 密码 */} -
- - setFormData({ ...formData, Password: e.target.value })} - placeholder='Emby 密码' - 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' - /> -
+ {/* 用户 ID */} +
+ + setFormData({ ...formData, UserId: e.target.value })} + placeholder='aab507c58e874de6a9bd12388d72f4d2' + 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' + /> +

+ 从你的 Emby 抓包数据中获取用户 ID,通常在 URL 中如 /Users/[userId]/... +

+
+ + )} - {/* 用户 ID */} -
- - setFormData({ ...formData, UserId: e.target.value })} - placeholder='aab507c58e874de6a9bd12388d72f4d2' - 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' - /> -

- 从你的 Emby 抓包数据中获取用户 ID,通常在 URL 中如 /Users/[userId]/... -

-
+ {/* 账号认证模式 */} + {authMode === 'password' && ( + <> + {/* 用户名 */} +
+ + setFormData({ ...formData, Username: e.target.value })} + placeholder='Emby 用户名' + 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' + /> +
+ + {/* 密码 */} +
+ + setFormData({ ...formData, Password: e.target.value })} + placeholder='Emby 密码(如果账号没有密码可留空)' + 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' + /> +

+ 如果 Emby 账号没有设置密码,可以留空 +

+
+ + )} {/* 启用开关 */}
diff --git a/src/app/api/admin/emby/route.ts b/src/app/api/admin/emby/route.ts index a7a224e..614207e 100644 --- a/src/app/api/admin/emby/route.ts +++ b/src/app/api/admin/emby/route.ts @@ -52,9 +52,9 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: '请填写 Emby 服务器地址' }, { status: 400 }); } - if (!ApiKey && (!Username || !Password)) { + if (!ApiKey && !Username) { return NextResponse.json( - { error: '请填写 API Key 或用户名密码' }, + { error: '请填写 API Key 或用户名' }, { status: 400 } ); } @@ -69,9 +69,9 @@ export async function POST(request: NextRequest) { const client = new EmbyClient(testConfig); // 如果使用用户名密码,先认证 - if (!ApiKey && Username && Password) { + if (!ApiKey && Username) { try { - await client.authenticate(Username, Password); + await client.authenticate(Username, Password || ''); } catch (error) { return NextResponse.json( { success: false, message: 'Emby 认证失败: ' + (error as Error).message }, diff --git a/src/lib/emby.client.ts b/src/lib/emby.client.ts index 13ef95a..067458a 100644 --- a/src/lib/emby.client.ts +++ b/src/lib/emby.client.ts @@ -115,9 +115,9 @@ export class EmbyClient { // 如果有 AuthToken,假设它是有效的 if (this.authToken) return; - // 如果有用户名和密码,自动认证 - if (this.username && this.password) { - const authResult = await this.authenticate(this.username, this.password); + // 如果有用户名,自动认证(密码可选) + if (this.username) { + const authResult = await this.authenticate(this.username, this.password || ''); this.authToken = authResult.AccessToken; this.userId = authResult.User.Id; }