diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 3c5cce0..49958b2 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -267,6 +267,7 @@ interface SiteConfig { DoubanImageProxy: string; DisableYellowFilter: boolean; FluidSearch: boolean; + EnableWebLive: boolean; } // 视频源数据类型 @@ -3393,6 +3394,7 @@ const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig | DoubanImageProxy: '', DisableYellowFilter: false, FluidSearch: true, + EnableWebLive: false, }); // 豆瓣数据源相关状态 @@ -3455,6 +3457,7 @@ const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig | DoubanImageProxy: config.SiteConfig.DoubanImageProxy || '', DisableYellowFilter: config.SiteConfig.DisableYellowFilter || false, FluidSearch: config.SiteConfig.FluidSearch || true, + EnableWebLive: config.SiteConfig.EnableWebLive ?? false, }); } }, [config]); @@ -3907,6 +3910,40 @@ const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig |

+ {/* 启用网页直播 */} +
+
+ + +
+

+ 网页直播性能较差,会导致服务器内存泄露。 +

+
+ {/* 操作按钮 */}
diff --git a/src/app/api/admin/site/route.ts b/src/app/api/admin/site/route.ts index b06539a..003ddb3 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, + EnableWebLive, } = body as { SiteName: string; Announcement: string; @@ -50,6 +51,7 @@ export async function POST(request: NextRequest) { DoubanImageProxy: string; DisableYellowFilter: boolean; FluidSearch: boolean; + EnableWebLive: boolean; }; // 参数校验 @@ -93,6 +95,7 @@ export async function POST(request: NextRequest) { DoubanImageProxy, DisableYellowFilter, FluidSearch, + EnableWebLive: EnableWebLive ?? false, }; // 写入数据库 diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e24fcea..51ad3a9 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -54,6 +54,7 @@ export default async function RootLayout({ let disableYellowFilter = process.env.NEXT_PUBLIC_DISABLE_YELLOW_FILTER === 'true'; let fluidSearch = process.env.NEXT_PUBLIC_FLUID_SEARCH !== 'false'; + let enableWebLive = false; let customCategories = [] as { name: string; type: 'movie' | 'tv'; @@ -77,6 +78,7 @@ export default async function RootLayout({ query: category.query, })); fluidSearch = config.SiteConfig.FluidSearch; + enableWebLive = config.SiteConfig.EnableWebLive ?? false; } // 将运行时配置注入到全局 window 对象,供客户端在运行时读取 @@ -89,6 +91,7 @@ export default async function RootLayout({ DISABLE_YELLOW_FILTER: disableYellowFilter, CUSTOM_CATEGORIES: customCategories, FLUID_SEARCH: fluidSearch, + ENABLE_WEB_LIVE: enableWebLive, }; return ( diff --git a/src/app/live/page.tsx b/src/app/live/page.tsx index 58d4c61..5394016 100644 --- a/src/app/live/page.tsx +++ b/src/app/live/page.tsx @@ -1606,7 +1606,38 @@ const FavoriteIcon = ({ filled }: { filled: boolean }) => { export default function LivePage() { return ( Loading...
}> - + ); } + +function LivePageGuard() { + const [enabled, setEnabled] = useState(null); + + useEffect(() => { + const runtimeConfig = (window as any).RUNTIME_CONFIG; + setEnabled(!!runtimeConfig?.ENABLE_WEB_LIVE); + }, []); + + if (enabled === null) { + return
Loading...
; + } + + if (!enabled) { + return ( + +
+ +

+ 网页直播未开启 +

+

+ 当前站点未启用网页直播功能,请联系站点管理员开启。 +

+
+
+ ); + } + + return ; +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 04f006c..2160df0 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -145,24 +145,35 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => { label: '综艺', href: '/douban?type=show', }, - { - icon: Radio, - label: '直播', - href: '/live', - }, ]); useEffect(() => { const runtimeConfig = (window as any).RUNTIME_CONFIG; + if (runtimeConfig?.ENABLE_WEB_LIVE) { + setMenuItems((prevItems) => { + if (prevItems.some((item) => item.href === '/live')) return prevItems; + return [ + ...prevItems, + { + icon: Radio, + label: '直播', + href: '/live', + }, + ]; + }); + } if (runtimeConfig?.CUSTOM_CATEGORIES?.length > 0) { - setMenuItems((prevItems) => [ - ...prevItems, - { - icon: Star, - label: '自定义', - href: '/douban?type=custom', - }, - ]); + setMenuItems((prevItems) => { + if (prevItems.some((item) => item.href === '/douban?type=custom')) return prevItems; + return [ + ...prevItems, + { + icon: Star, + label: '自定义', + href: '/douban?type=custom', + }, + ]; + }); } }, []); diff --git a/src/lib/admin.types.ts b/src/lib/admin.types.ts index e29fa00..a79857e 100644 --- a/src/lib/admin.types.ts +++ b/src/lib/admin.types.ts @@ -16,6 +16,7 @@ export interface AdminConfig { DoubanImageProxy: string; DisableYellowFilter: boolean; FluidSearch: boolean; + EnableWebLive: boolean; }; UserConfig: { Users: {