feat(settings): settings-page-first open-network config, drop env-directed copy
This commit is contained in:
parent
95962b4aa4
commit
fd70f649ae
|
|
@ -17,7 +17,7 @@ MEDIA_SECRET_KEY=
|
||||||
PASSWORD_RESET_WEBHOOK_URL=
|
PASSWORD_RESET_WEBHOOK_URL=
|
||||||
|
|
||||||
# 弹弹play 开放弹幕网络(https://doc.dandanplay.com/open)
|
# 弹弹play 开放弹幕网络(https://doc.dandanplay.com/open)
|
||||||
# 未配置 AppId/AppSecret 时,弹幕接口返回 source=none「未配置开放网络」
|
# AppId/AppSecret 推荐在「账户设置」页配置(存库、即时生效,仅管理员);此处为可选的服务端兜底
|
||||||
OPEN_DANMAKU_APP_ID=
|
OPEN_DANMAKU_APP_ID=
|
||||||
OPEN_DANMAKU_APP_SECRET=
|
OPEN_DANMAKU_APP_SECRET=
|
||||||
# 可选:自定义开放弹幕 API 地址(默认 https://api.dandanplay.net)
|
# 可选:自定义开放弹幕 API 地址(默认 https://api.dandanplay.net)
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,10 @@ function Inner(props: { locale: Locale }) {
|
||||||
<h1 className="text-xl font-semibold">{t(locale, "danmaku.title")}</h1>
|
<h1 className="text-xl font-semibold">{t(locale, "danmaku.title")}</h1>
|
||||||
{openNetworkMissing && (
|
{openNetworkMissing && (
|
||||||
<div className="rounded-lg border border-amber-500/50 bg-amber-500/10 px-4 py-3 text-sm text-amber-800 dark:text-amber-200">
|
<div className="rounded-lg border border-amber-500/50 bg-amber-500/10 px-4 py-3 text-sm text-amber-800 dark:text-amber-200">
|
||||||
{t(locale, "danmaku.openNetworkNotConfigured")}
|
{t(locale, "danmaku.openNetworkNotConfigured")}{" "}
|
||||||
|
<a className="underline underline-offset-2" href={`/${locale}/settings`}>
|
||||||
|
{t(locale, "auth.menu.settings")}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Card className="max-w-md space-y-5 p-6">
|
<Card className="max-w-md space-y-5 p-6">
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ export const en: Record<MessageKey, string> = {
|
||||||
"danmaku.blockTypeTop": "Top",
|
"danmaku.blockTypeTop": "Top",
|
||||||
"danmaku.blockTypeBottom": "Bottom",
|
"danmaku.blockTypeBottom": "Bottom",
|
||||||
"danmaku.openNetworkNotConfigured":
|
"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":
|
"danmaku.serverPrefsHint":
|
||||||
"Preferences are stored on this account; watch-page filters and display follow this config.",
|
"Preferences are stored on this account; watch-page filters and display follow this config.",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,8 @@ export const zhCN = {
|
||||||
"danmaku.blockTypeScroll": "滚动",
|
"danmaku.blockTypeScroll": "滚动",
|
||||||
"danmaku.blockTypeTop": "顶部",
|
"danmaku.blockTypeTop": "顶部",
|
||||||
"danmaku.blockTypeBottom": "底部",
|
"danmaku.blockTypeBottom": "底部",
|
||||||
"danmaku.openNetworkNotConfigured": "未配置开放弹幕网络服务端凭据,在线弹幕可能为空。",
|
"danmaku.openNetworkNotConfigured":
|
||||||
|
"未配置开放弹幕网络凭据,在线弹幕可能为空。管理员可前往设置:",
|
||||||
"danmaku.serverPrefsHint": "偏好保存在当前账号下,播放页过滤与显示沿用此配置。",
|
"danmaku.serverPrefsHint": "偏好保存在当前账号下,播放页过滤与显示沿用此配置。",
|
||||||
|
|
||||||
"auth.login.title": "登录",
|
"auth.login.title": "登录",
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ describe("danmakuService.fetch", () => {
|
||||||
vi.mocked(hasOpenCredentials).mockReturnValue(false);
|
vi.mocked(hasOpenCredentials).mockReturnValue(false);
|
||||||
const r = await danmakuService.fetch("u1", "m1");
|
const r = await danmakuService.fetch("u1", "m1");
|
||||||
expect(r.source).toBe("none");
|
expect(r.source).toBe("none");
|
||||||
expect(r.message).toContain("OPEN_DANMAKU_APP_ID");
|
expect(r.message).toContain("账户设置");
|
||||||
expect(openMatch).not.toHaveBeenCalled();
|
expect(openMatch).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -642,7 +642,7 @@ describe("danmakuService.fetch 同名侧车", () => {
|
||||||
vi.mocked(hasOpenCredentials).mockReturnValue(false);
|
vi.mocked(hasOpenCredentials).mockReturnValue(false);
|
||||||
const r = await danmakuService.fetch("u1", "m1");
|
const r = await danmakuService.fetch("u1", "m1");
|
||||||
expect(r.source).toBe("none");
|
expect(r.source).toBe("none");
|
||||||
expect(r.message).toContain("OPEN_DANMAKU_APP_ID");
|
expect(r.message).toContain("账户设置");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("已有 local-xml 时不扫描侧车", async () => {
|
it("已有 local-xml 时不扫描侧车", async () => {
|
||||||
|
|
|
||||||
|
|
@ -160,8 +160,7 @@ export const danmakuService = {
|
||||||
ok: true,
|
ok: true,
|
||||||
source: "none",
|
source: "none",
|
||||||
xml: "",
|
xml: "",
|
||||||
message:
|
message: "未配置开放弹幕网络:管理员请在「账户设置」页填写 AppId / AppSecret",
|
||||||
"未配置开放弹幕网络:服务端需设置 OPEN_DANMAKU_APP_ID / OPEN_DANMAKU_APP_SECRET",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,6 +364,8 @@ export const danmakuService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
async getPrefs(userId: string): Promise<DanmakuSettingsOutput> {
|
async getPrefs(userId: string): Promise<DanmakuSettingsOutput> {
|
||||||
|
// 全新启动且凭据只存在库内时,先把库内凭据注入运行时,状态显示才准确
|
||||||
|
await ensureOpenRuntime();
|
||||||
const row = await danmakuPrefsDao.getByUser(userId);
|
const row = await danmakuPrefsDao.getByUser(userId);
|
||||||
return {
|
return {
|
||||||
enabled: row?.enabled ?? true,
|
enabled: row?.enabled ?? true,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
openMatch,
|
openMatch,
|
||||||
rankCandidates,
|
rankCandidates,
|
||||||
} from "@app/danmaku";
|
} from "@app/danmaku";
|
||||||
|
import { ensureOpenRuntime } from "./settings.service.js";
|
||||||
import { parseEpisodeFromFilename, type BatchResult, type DanmakuMatchOutput } from "@app/types";
|
import { parseEpisodeFromFilename, type BatchResult, type DanmakuMatchOutput } from "@app/types";
|
||||||
import { remoteFileHash } from "./danmaku.service.js";
|
import { remoteFileHash } from "./danmaku.service.js";
|
||||||
|
|
||||||
|
|
@ -192,14 +193,14 @@ export const scrapeService = {
|
||||||
* 未中且有 Bangumi 绑定时走 bgmtv 桥按集数兜底。写 dandanplayEpisodeId + 元数据。
|
* 未中且有 Bangumi 绑定时走 bgmtv 桥按集数兜底。写 dandanplayEpisodeId + 元数据。
|
||||||
*/
|
*/
|
||||||
async matchDandanplay(userId: string, mediaItemId: string): Promise<DanmakuMatchOutput> {
|
async matchDandanplay(userId: string, mediaItemId: string): Promise<DanmakuMatchOutput> {
|
||||||
|
await ensureOpenRuntime();
|
||||||
const row = await mediaItemDao.getByIdForUser(mediaItemId, userId);
|
const row = await mediaItemDao.getByIdForUser(mediaItemId, userId);
|
||||||
if (!row) throw new TRPCError({ code: "NOT_FOUND", message: "媒体不存在" });
|
if (!row) throw new TRPCError({ code: "NOT_FOUND", message: "媒体不存在" });
|
||||||
if (!hasOpenCredentials()) {
|
if (!hasOpenCredentials()) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
matched: false,
|
matched: false,
|
||||||
message:
|
message: "未配置开放弹幕网络:管理员请在「账户设置」页填写 AppId / AppSecret",
|
||||||
"未配置开放弹幕网络:服务端需设置 OPEN_DANMAKU_APP_ID / OPEN_DANMAKU_APP_SECRET",
|
|
||||||
candidates: [],
|
candidates: [],
|
||||||
highConfidence: false,
|
highConfidence: false,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue