diff --git a/.env.example b/.env.example index 52946f3..faec802 100644 --- a/.env.example +++ b/.env.example @@ -17,7 +17,7 @@ MEDIA_SECRET_KEY= PASSWORD_RESET_WEBHOOK_URL= # 弹弹play 开放弹幕网络(https://doc.dandanplay.com/open) -# 未配置 AppId/AppSecret 时,弹幕接口返回 source=none「未配置开放网络」 +# AppId/AppSecret 推荐在「账户设置」页配置(存库、即时生效,仅管理员);此处为可选的服务端兜底 OPEN_DANMAKU_APP_ID= OPEN_DANMAKU_APP_SECRET= # 可选:自定义开放弹幕 API 地址(默认 https://api.dandanplay.net) diff --git a/app/web/src/components/pages/DanmakuSettingsBody.tsx b/app/web/src/components/pages/DanmakuSettingsBody.tsx index c1ba8c1..a544ce4 100644 --- a/app/web/src/components/pages/DanmakuSettingsBody.tsx +++ b/app/web/src/components/pages/DanmakuSettingsBody.tsx @@ -150,7 +150,10 @@ function Inner(props: { locale: Locale }) {

{t(locale, "danmaku.title")}

{openNetworkMissing && (
- {t(locale, "danmaku.openNetworkNotConfigured")} + {t(locale, "danmaku.openNetworkNotConfigured")}{" "} + + {t(locale, "auth.menu.settings")} +
)} diff --git a/packages/i18n/src/messages/en.ts b/packages/i18n/src/messages/en.ts index 8d0019c..f3a8f20 100644 --- a/packages/i18n/src/messages/en.ts +++ b/packages/i18n/src/messages/en.ts @@ -251,7 +251,7 @@ export const en: Record = { "danmaku.blockTypeTop": "Top", "danmaku.blockTypeBottom": "Bottom", "danmaku.openNetworkNotConfigured": - "Open danmaku network credentials are not configured; online danmaku may be empty.", + "Open danmaku network credentials are not configured; online danmaku may be empty. Admins can set them in Settings:", "danmaku.serverPrefsHint": "Preferences are stored on this account; watch-page filters and display follow this config.", diff --git a/packages/i18n/src/messages/zh-CN.ts b/packages/i18n/src/messages/zh-CN.ts index 794ec18..fdca021 100644 --- a/packages/i18n/src/messages/zh-CN.ts +++ b/packages/i18n/src/messages/zh-CN.ts @@ -244,7 +244,8 @@ export const zhCN = { "danmaku.blockTypeScroll": "滚动", "danmaku.blockTypeTop": "顶部", "danmaku.blockTypeBottom": "底部", - "danmaku.openNetworkNotConfigured": "未配置开放弹幕网络服务端凭据,在线弹幕可能为空。", + "danmaku.openNetworkNotConfigured": + "未配置开放弹幕网络凭据,在线弹幕可能为空。管理员可前往设置:", "danmaku.serverPrefsHint": "偏好保存在当前账号下,播放页过滤与显示沿用此配置。", "auth.login.title": "登录", diff --git a/packages/trpc/src/services/danmaku.service.test.ts b/packages/trpc/src/services/danmaku.service.test.ts index 3d96616..4039a5d 100644 --- a/packages/trpc/src/services/danmaku.service.test.ts +++ b/packages/trpc/src/services/danmaku.service.test.ts @@ -239,7 +239,7 @@ describe("danmakuService.fetch", () => { vi.mocked(hasOpenCredentials).mockReturnValue(false); const r = await danmakuService.fetch("u1", "m1"); expect(r.source).toBe("none"); - expect(r.message).toContain("OPEN_DANMAKU_APP_ID"); + expect(r.message).toContain("账户设置"); expect(openMatch).not.toHaveBeenCalled(); }); @@ -642,7 +642,7 @@ describe("danmakuService.fetch 同名侧车", () => { vi.mocked(hasOpenCredentials).mockReturnValue(false); const r = await danmakuService.fetch("u1", "m1"); expect(r.source).toBe("none"); - expect(r.message).toContain("OPEN_DANMAKU_APP_ID"); + expect(r.message).toContain("账户设置"); }); it("已有 local-xml 时不扫描侧车", async () => { diff --git a/packages/trpc/src/services/danmaku.service.ts b/packages/trpc/src/services/danmaku.service.ts index 4f695c6..f932537 100644 --- a/packages/trpc/src/services/danmaku.service.ts +++ b/packages/trpc/src/services/danmaku.service.ts @@ -160,8 +160,7 @@ export const danmakuService = { ok: true, source: "none", xml: "", - message: - "未配置开放弹幕网络:服务端需设置 OPEN_DANMAKU_APP_ID / OPEN_DANMAKU_APP_SECRET", + message: "未配置开放弹幕网络:管理员请在「账户设置」页填写 AppId / AppSecret", }; } @@ -365,6 +364,8 @@ export const danmakuService = { }, async getPrefs(userId: string): Promise { + // 全新启动且凭据只存在库内时,先把库内凭据注入运行时,状态显示才准确 + await ensureOpenRuntime(); const row = await danmakuPrefsDao.getByUser(userId); return { enabled: row?.enabled ?? true, diff --git a/packages/trpc/src/services/scrape.service.ts b/packages/trpc/src/services/scrape.service.ts index 7d15a07..d0dd730 100644 --- a/packages/trpc/src/services/scrape.service.ts +++ b/packages/trpc/src/services/scrape.service.ts @@ -7,6 +7,7 @@ import { openMatch, rankCandidates, } from "@app/danmaku"; +import { ensureOpenRuntime } from "./settings.service.js"; import { parseEpisodeFromFilename, type BatchResult, type DanmakuMatchOutput } from "@app/types"; import { remoteFileHash } from "./danmaku.service.js"; @@ -192,14 +193,14 @@ export const scrapeService = { * 未中且有 Bangumi 绑定时走 bgmtv 桥按集数兜底。写 dandanplayEpisodeId + 元数据。 */ async matchDandanplay(userId: string, mediaItemId: string): Promise { + await ensureOpenRuntime(); const row = await mediaItemDao.getByIdForUser(mediaItemId, userId); if (!row) throw new TRPCError({ code: "NOT_FOUND", message: "媒体不存在" }); if (!hasOpenCredentials()) { return { ok: false, matched: false, - message: - "未配置开放弹幕网络:服务端需设置 OPEN_DANMAKU_APP_ID / OPEN_DANMAKU_APP_SECRET", + message: "未配置开放弹幕网络:管理员请在「账户设置」页填写 AppId / AppSecret", candidates: [], highConfidence: false, };