diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index 4721044..b9700ce 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -341,6 +341,7 @@ interface SiteConfig {
DoubanImageProxy: string;
DisableYellowFilter: boolean;
FluidSearch: boolean;
+ DanmakuSourceType?: 'builtin' | 'custom';
DanmakuApiBase: string;
DanmakuApiToken: string;
TMDBApiKey?: string;
@@ -7923,7 +7924,8 @@ const SiteConfigComponent = ({
DoubanImageProxy: '',
DisableYellowFilter: false,
FluidSearch: true,
- DanmakuApiBase: 'http://localhost:9321',
+ DanmakuSourceType: 'builtin',
+ DanmakuApiBase: 'https://mtvpls-danmu.netlify.app/87654321',
DanmakuApiToken: '87654321',
TMDBApiKey: '',
TMDBProxy: '',
@@ -8018,6 +8020,7 @@ const SiteConfigComponent = ({
DoubanImageProxy: config.SiteConfig.DoubanImageProxy || '',
DisableYellowFilter: config.SiteConfig.DisableYellowFilter || false,
FluidSearch: config.SiteConfig.FluidSearch || true,
+ DanmakuSourceType: config.SiteConfig.DanmakuSourceType || 'custom',
DanmakuApiBase:
config.SiteConfig.DanmakuApiBase || 'http://localhost:9321',
DanmakuApiToken: config.SiteConfig.DanmakuApiToken || '87654321',
@@ -8567,57 +8570,102 @@ const SiteConfigComponent = ({
弹幕配置
- {/* 弹幕 API 地址 */}
-
-
-
+
+
+
- {/* 弹幕 API Token */}
-
-
-
- setSiteSettings((prev) => ({
- ...prev,
- DanmakuApiToken: e.target.value,
- }))
- }
- 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-green-500 focus:border-transparent'
- />
-
- 弹幕服务器的访问令牌,默认为 87654321
+ {siteSettings.DanmakuSourceType !== 'custom' && (
+
+ ⚠️ 内置弹幕源为多人共享服务,稳定性可能受使用高峰影响,建议自行部署后使用自定义源。
-
+ )}
+
+ {siteSettings.DanmakuSourceType === 'custom' && (
+ <>
+ {/* 弹幕 API 地址 */}
+
+
+
+ setSiteSettings((prev) => ({
+ ...prev,
+ DanmakuApiBase: e.target.value,
+ }))
+ }
+ 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-green-500 focus:border-transparent'
+ />
+
+ 自定义弹幕服务器的 API 地址。API部署参考
+
+ danmu_api
+
+
+
+
+ {/* 弹幕 API Token */}
+
+
+
+ setSiteSettings((prev) => ({
+ ...prev,
+ DanmakuApiToken: e.target.value,
+ }))
+ }
+ 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-green-500 focus:border-transparent'
+ />
+
+ 自定义弹幕服务器的访问令牌,默认为 87654321
+
+
+ >
+ )}
diff --git a/src/app/api/admin/site/route.ts b/src/app/api/admin/site/route.ts
index 75ce279..b51a4f5 100644
--- a/src/app/api/admin/site/route.ts
+++ b/src/app/api/admin/site/route.ts
@@ -39,6 +39,7 @@ export async function POST(request: NextRequest) {
DoubanImageProxy,
DisableYellowFilter,
FluidSearch,
+ DanmakuSourceType,
DanmakuApiBase,
DanmakuApiToken,
TMDBApiKey,
@@ -86,6 +87,7 @@ export async function POST(request: NextRequest) {
DoubanImageProxy: string;
DisableYellowFilter: boolean;
FluidSearch: boolean;
+ DanmakuSourceType?: 'builtin' | 'custom';
DanmakuApiBase: string;
DanmakuApiToken: string;
TMDBApiKey?: string;
@@ -136,6 +138,9 @@ export async function POST(request: NextRequest) {
typeof DoubanImageProxy !== 'string' ||
typeof DisableYellowFilter !== 'boolean' ||
typeof FluidSearch !== 'boolean' ||
+ (DanmakuSourceType !== undefined &&
+ DanmakuSourceType !== 'builtin' &&
+ DanmakuSourceType !== 'custom') ||
typeof DanmakuApiBase !== 'string' ||
typeof DanmakuApiToken !== 'string' ||
(TMDBApiKey !== undefined && typeof TMDBApiKey !== 'string') ||
@@ -195,6 +200,7 @@ export async function POST(request: NextRequest) {
DoubanImageProxy,
DisableYellowFilter,
FluidSearch,
+ DanmakuSourceType,
DanmakuApiBase,
DanmakuApiToken,
TMDBApiKey,
diff --git a/src/app/api/danmaku/comment/route.ts b/src/app/api/danmaku/comment/route.ts
index c56059a..4c754f3 100644
--- a/src/app/api/danmaku/comment/route.ts
+++ b/src/app/api/danmaku/comment/route.ts
@@ -2,6 +2,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
+import { getDanmakuApiBaseUrl } from '@/lib/danmaku/config';
export const runtime = 'nodejs';
@@ -50,13 +51,7 @@ export async function GET(request: NextRequest) {
// 从数据库读取弹幕配置
const config = await getConfig();
- const { DanmakuApiBase, DanmakuApiToken } = config.SiteConfig;
-
- // 构建 API URL
- const baseUrl =
- DanmakuApiToken === '87654321'
- ? DanmakuApiBase
- : `${DanmakuApiBase}/${DanmakuApiToken}`;
+ const baseUrl = getDanmakuApiBaseUrl(config.SiteConfig);
let apiUrl: string;
diff --git a/src/app/api/danmaku/episodes/route.ts b/src/app/api/danmaku/episodes/route.ts
index b28e064..181e93b 100644
--- a/src/app/api/danmaku/episodes/route.ts
+++ b/src/app/api/danmaku/episodes/route.ts
@@ -2,6 +2,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
+import { getDanmakuApiBaseUrl } from '@/lib/danmaku/config';
export const runtime = 'nodejs';
@@ -28,13 +29,7 @@ export async function GET(request: NextRequest) {
// 从数据库读取弹幕配置
const config = await getConfig();
- const { DanmakuApiBase, DanmakuApiToken } = config.SiteConfig;
-
- // 构建 API URL
- const baseUrl =
- DanmakuApiToken === '87654321'
- ? DanmakuApiBase
- : `${DanmakuApiBase}/${DanmakuApiToken}`;
+ const baseUrl = getDanmakuApiBaseUrl(config.SiteConfig);
const apiUrl = `${baseUrl}/api/v2/bangumi/${animeId}`;
diff --git a/src/app/api/danmaku/match/route.ts b/src/app/api/danmaku/match/route.ts
index 972bf00..03b16b5 100644
--- a/src/app/api/danmaku/match/route.ts
+++ b/src/app/api/danmaku/match/route.ts
@@ -2,6 +2,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
+import { getDanmakuApiBaseUrl } from '@/lib/danmaku/config';
export const runtime = 'nodejs';
@@ -25,13 +26,7 @@ export async function POST(request: NextRequest) {
// 从数据库读取弹幕配置
const config = await getConfig();
- const { DanmakuApiBase, DanmakuApiToken } = config.SiteConfig;
-
- // 构建 API URL
- const baseUrl =
- DanmakuApiToken === '87654321'
- ? DanmakuApiBase
- : `${DanmakuApiBase}/${DanmakuApiToken}`;
+ const baseUrl = getDanmakuApiBaseUrl(config.SiteConfig);
const apiUrl = `${baseUrl}/api/v2/match`;
diff --git a/src/app/api/danmaku/search/route.ts b/src/app/api/danmaku/search/route.ts
index ecda7ef..5c025d5 100644
--- a/src/app/api/danmaku/search/route.ts
+++ b/src/app/api/danmaku/search/route.ts
@@ -2,6 +2,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
+import { getDanmakuApiBaseUrl } from '@/lib/danmaku/config';
export const runtime = 'nodejs';
@@ -24,13 +25,7 @@ export async function GET(request: NextRequest) {
// 从数据库读取弹幕配置
const config = await getConfig();
- const { DanmakuApiBase, DanmakuApiToken } = config.SiteConfig;
-
- // 构建 API URL
- const baseUrl =
- DanmakuApiToken === '87654321'
- ? DanmakuApiBase
- : `${DanmakuApiBase}/${DanmakuApiToken}`;
+ const baseUrl = getDanmakuApiBaseUrl(config.SiteConfig);
const apiUrl = `${baseUrl}/api/v2/search/anime?keyword=${encodeURIComponent(keyword)}`;
diff --git a/src/lib/admin.types.ts b/src/lib/admin.types.ts
index 117f797..33b8332 100644
--- a/src/lib/admin.types.ts
+++ b/src/lib/admin.types.ts
@@ -17,6 +17,7 @@ export interface AdminConfig {
DisableYellowFilter: boolean;
FluidSearch: boolean;
// 弹幕配置
+ DanmakuSourceType?: 'builtin' | 'custom';
DanmakuApiBase: string;
DanmakuApiToken: string;
// TMDB配置
diff --git a/src/lib/config.ts b/src/lib/config.ts
index 25090aa..c35c9c2 100644
--- a/src/lib/config.ts
+++ b/src/lib/config.ts
@@ -4,6 +4,8 @@ import { db } from '@/lib/db';
import { AdminConfig } from './admin.types';
+const BUILTIN_DANMAKU_API_BASE = 'https://mtvpls-danmu.netlify.app/87654321';
+
export interface ApiSite {
key: string;
api: string;
@@ -223,6 +225,9 @@ async function getInitConfig(configFile: string, subConfig: {
} catch (e) {
cfgFile = {} as ConfigFileStruct;
}
+ const hasCustomDanmakuEnv = Boolean(
+ process.env.DANMAKU_API_BASE || process.env.DANMAKU_API_TOKEN
+ );
const adminConfig: AdminConfig = {
ConfigFile: configSource,
ConfigSubscribtion: subConfig,
@@ -245,7 +250,10 @@ async function getInitConfig(configFile: string, subConfig: {
FluidSearch:
process.env.NEXT_PUBLIC_FLUID_SEARCH !== 'false',
// 弹幕配置
- DanmakuApiBase: process.env.DANMAKU_API_BASE || 'http://localhost:9321',
+ DanmakuSourceType: hasCustomDanmakuEnv ? 'custom' : 'builtin',
+ DanmakuApiBase:
+ process.env.DANMAKU_API_BASE ||
+ (hasCustomDanmakuEnv ? 'http://localhost:9321' : BUILTIN_DANMAKU_API_BASE),
DanmakuApiToken: process.env.DANMAKU_API_TOKEN || '87654321',
// TMDB配置
TMDBApiKey: process.env.TMDB_API_KEY || '',
@@ -439,7 +447,8 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
DoubanImageProxy: '',
DisableYellowFilter: false,
FluidSearch: true,
- DanmakuApiBase: 'http://localhost:9321',
+ DanmakuSourceType: 'builtin',
+ DanmakuApiBase: BUILTIN_DANMAKU_API_BASE,
DanmakuApiToken: '87654321',
PansouApiUrl: '',
PansouUsername: '',
@@ -461,8 +470,14 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
};
}
// 确保弹幕配置存在
+ if (adminConfig.SiteConfig.DanmakuSourceType === undefined) {
+ adminConfig.SiteConfig.DanmakuSourceType = 'custom';
+ }
if (!adminConfig.SiteConfig.DanmakuApiBase) {
- adminConfig.SiteConfig.DanmakuApiBase = 'http://localhost:9321';
+ adminConfig.SiteConfig.DanmakuApiBase =
+ adminConfig.SiteConfig.DanmakuSourceType === 'builtin'
+ ? BUILTIN_DANMAKU_API_BASE
+ : 'http://localhost:9321';
}
if (!adminConfig.SiteConfig.DanmakuApiToken) {
adminConfig.SiteConfig.DanmakuApiToken = '87654321';
diff --git a/src/lib/danmaku/config.ts b/src/lib/danmaku/config.ts
new file mode 100644
index 0000000..0e9dec4
--- /dev/null
+++ b/src/lib/danmaku/config.ts
@@ -0,0 +1,19 @@
+import type { AdminConfig } from '@/lib/admin.types';
+
+export const BUILTIN_DANMAKU_API_BASE = 'https://mtvpls-danmu.netlify.app/87654321';
+export const BUILTIN_DANMAKU_API_TOKEN = '87654321';
+
+function trimTrailingSlash(value: string) {
+ return value.replace(/\/+$/, '');
+}
+
+export function getDanmakuApiBaseUrl(siteConfig: AdminConfig['SiteConfig']) {
+ if (siteConfig.DanmakuSourceType === 'builtin') {
+ return BUILTIN_DANMAKU_API_BASE;
+ }
+
+ const base = trimTrailingSlash(siteConfig.DanmakuApiBase || 'http://localhost:9321');
+ const token = (siteConfig.DanmakuApiToken || BUILTIN_DANMAKU_API_TOKEN).trim();
+
+ return token === BUILTIN_DANMAKU_API_TOKEN ? base : `${base}/${token}`;
+}