diff --git a/D1初始化.md b/D1初始化.md
new file mode 100644
index 0000000..f6dc790
--- /dev/null
+++ b/D1初始化.md
@@ -0,0 +1,75 @@
+```sql
+CREATE TABLE IF NOT EXISTS users (
+ username TEXT PRIMARY KEY,
+ password TEXT NOT NULL,
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
+ );
+
+ CREATE TABLE IF NOT EXISTS play_records (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ key TEXT NOT NULL,
+ title TEXT NOT NULL,
+ source_name TEXT NOT NULL,
+ cover TEXT NOT NULL,
+ year TEXT NOT NULL,
+ index_episode INTEGER NOT NULL,
+ total_episodes INTEGER NOT NULL,
+ play_time INTEGER NOT NULL,
+ total_time INTEGER NOT NULL,
+ save_time INTEGER NOT NULL,
+ search_title TEXT,
+ UNIQUE(username, key)
+ );
+
+ CREATE TABLE IF NOT EXISTS favorites (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ key TEXT NOT NULL,
+ title TEXT NOT NULL,
+ source_name TEXT NOT NULL,
+ cover TEXT NOT NULL,
+ year TEXT NOT NULL,
+ total_episodes INTEGER NOT NULL,
+ save_time INTEGER NOT NULL,
+ UNIQUE(username, key)
+ );
+
+ CREATE TABLE IF NOT EXISTS search_history (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ keyword TEXT NOT NULL,
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
+ UNIQUE(username, keyword)
+ );
+
+ CREATE TABLE IF NOT EXISTS admin_config (
+ id INTEGER PRIMARY KEY DEFAULT 1,
+ config TEXT NOT NULL,
+ updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
+ );
+
+ -- 基本索引
+ CREATE INDEX IF NOT EXISTS idx_play_records_username ON play_records(username);
+ CREATE INDEX IF NOT EXISTS idx_favorites_username ON favorites(username);
+ CREATE INDEX IF NOT EXISTS idx_search_history_username ON search_history(username);
+
+ -- 复合索引优化查询性能
+ -- 播放记录:用户名+键值的复合索引,用于快速查找特定记录
+ CREATE INDEX IF NOT EXISTS idx_play_records_username_key ON play_records(username, key);
+ -- 播放记录:用户名+保存时间的复合索引,用于按时间排序的查询
+ CREATE INDEX IF NOT EXISTS idx_play_records_username_save_time ON play_records(username, save_time DESC);
+
+ -- 收藏:用户名+键值的复合索引,用于快速查找特定收藏
+ CREATE INDEX IF NOT EXISTS idx_favorites_username_key ON favorites(username, key);
+ -- 收藏:用户名+保存时间的复合索引,用于按时间排序的查询
+ CREATE INDEX IF NOT EXISTS idx_favorites_username_save_time ON favorites(username, save_time DESC);
+
+ -- 搜索历史:用户名+关键词的复合索引,用于快速查找/删除特定搜索记录
+ CREATE INDEX IF NOT EXISTS idx_search_history_username_keyword ON search_history(username, keyword);
+ -- 搜索历史:用户名+创建时间的复合索引,用于按时间排序的查询
+ CREATE INDEX IF NOT EXISTS idx_search_history_username_created_at ON search_history(username, created_at DESC);
+
+ -- 搜索历史清理查询的优化索引
+ CREATE INDEX IF NOT EXISTS idx_search_history_username_id_created_at ON search_history(username, id, created_at DESC);
+```
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index bc9859f..8e4f490 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -126,6 +126,11 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
// 当前登录用户名
const currentUsername = getAuthInfoFromBrowserCookie()?.username || null;
+ // 检测存储类型是否为 d1
+ const isD1Storage =
+ typeof window !== 'undefined' &&
+ (window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'd1';
+
useEffect(() => {
if (config?.UserConfig) {
setUserSettings({
@@ -285,18 +290,29 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
注册设置
-
+
允许新用户注册
+ {isD1Storage && (
+
+ (D1 环境下不可修改)
+
+ )}
+ !isD1Storage &&
toggleAllowRegister(!userSettings.enableRegistration)
}
+ disabled={isD1Storage}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
userSettings.enableRegistration
? 'bg-green-600'
: 'bg-gray-200 dark:bg-gray-700'
- }`}
+ } ${isD1Storage ? 'opacity-50 cursor-not-allowed' : ''}`}
>
{
// 保存状态
const [saving, setSaving] = useState(false);
+ // 检测存储类型是否为 d1
+ const isD1Storage =
+ typeof window !== 'undefined' &&
+ (window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'd1';
+
useEffect(() => {
if (config?.SiteConfig) {
setSiteSettings(config.SiteConfig);
@@ -978,34 +999,60 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
{/* 站点名称 */}
-
+
站点名称
+ {isD1Storage && (
+
+ (D1 环境下不可修改)
+
+ )}
+ !isD1Storage &&
setSiteSettings((prev) => ({ ...prev, SiteName: 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'
+ disabled={isD1Storage}
+ 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 ${
+ isD1Storage ? 'opacity-50 cursor-not-allowed' : ''
+ }`}
/>
{/* 站点公告 */}
-
+
站点公告
+ {isD1Storage && (
+
+ (D1 环境下不可修改)
+
+ )}
@@ -1049,21 +1096,32 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
{/* 默认按标题和年份聚合 */}
-
+
搜索结果默认按标题和年份聚合
+ {isD1Storage && (
+
+ (D1 环境下不可修改)
+
+ )}
+ !isD1Storage &&
setSiteSettings((prev) => ({
...prev,
SearchResultDefaultAggregate: !prev.SearchResultDefaultAggregate,
}))
}
+ disabled={isD1Storage}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
siteSettings.SearchResultDefaultAggregate
? 'bg-green-600'
: 'bg-gray-200 dark:bg-gray-700'
- }`}
+ } ${isD1Storage ? 'opacity-50 cursor-not-allowed' : ''}`}
>
{
{saving ? '保存中…' : '保存'}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index efd21f5..2149a8e 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -13,10 +13,14 @@ const inter = Inter({ subsets: ['latin'] });
// 动态生成 metadata,支持配置更新后的标题变化
export async function generateMetadata(): Promise {
- const config = await getConfig();
+ let siteName = process.env.NEXT_PUBLIC_SITE_NAME;
+ if (process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1') {
+ const config = await getConfig();
+ siteName = config.SiteConfig.SiteName;
+ }
return {
- title: config.SiteConfig.SiteName,
+ title: siteName,
description: '影视聚合',
manifest: '/manifest.json',
};
@@ -31,15 +35,26 @@ export default async function RootLayout({
}: {
children: React.ReactNode;
}) {
- const config = await getConfig();
- const siteName = config.SiteConfig.SiteName;
- const announcement = config.SiteConfig.Announcement;
+ let siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV';
+ let announcement =
+ process.env.ANNOUNCEMENT ||
+ '本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
+ let enableRegister = process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true';
+ let aggregateSearchResult =
+ process.env.NEXT_PUBLIC_AGGREGATE_SEARCH_RESULT !== 'false';
+ if (process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1') {
+ const config = await getConfig();
+ siteName = config.SiteConfig.SiteName;
+ announcement = config.SiteConfig.Announcement;
+ enableRegister = config.UserConfig.AllowRegister;
+ aggregateSearchResult = config.SiteConfig.SearchResultDefaultAggregate;
+ }
// 将运行时配置注入到全局 window 对象,供客户端在运行时读取
const runtimeConfig = {
STORAGE_TYPE: process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage',
- ENABLE_REGISTER: config.UserConfig.AllowRegister,
- AGGREGATE_SEARCH_RESULT: config.SiteConfig.SearchResultDefaultAggregate,
+ ENABLE_REGISTER: enableRegister,
+ AGGREGATE_SEARCH_RESULT: aggregateSearchResult,
};
return (
diff --git a/src/lib/config.ts b/src/lib/config.ts
index 3094831..4655e18 100644
--- a/src/lib/config.ts
+++ b/src/lib/config.ts
@@ -68,128 +68,126 @@ async function initConfig() {
if (storageType !== 'localstorage') {
// 数据库存储,读取并补全管理员配置
const storage = getStorage();
- (async () => {
- try {
- // 尝试从数据库获取管理员配置
- let adminConfig: AdminConfig | null = null;
- if (storage && typeof (storage as any).getAdminConfig === 'function') {
- adminConfig = await (storage as any).getAdminConfig();
+
+ try {
+ // 尝试从数据库获取管理员配置
+ let adminConfig: AdminConfig | null = null;
+ if (storage && typeof (storage as any).getAdminConfig === 'function') {
+ adminConfig = await (storage as any).getAdminConfig();
+ }
+
+ // 获取所有用户名,用于补全 Users
+ let userNames: string[] = [];
+ if (storage && typeof (storage as any).getAllUsers === 'function') {
+ try {
+ userNames = await (storage as any).getAllUsers();
+ } catch (e) {
+ console.error('获取用户列表失败:', e);
}
+ }
- // 获取所有用户名,用于补全 Users
- let userNames: string[] = [];
- if (storage && typeof (storage as any).getAllUsers === 'function') {
- try {
- userNames = await (storage as any).getAllUsers();
- } catch (e) {
- console.error('获取用户列表失败:', e);
- }
- }
+ // 从文件中获取源信息,用于补全源
+ const apiSiteEntries = Object.entries(fileConfig.api_site);
- // 从文件中获取源信息,用于补全源
- const apiSiteEntries = Object.entries(fileConfig.api_site);
-
- if (adminConfig) {
- // 补全 SourceConfig
- const existed = new Set(
- (adminConfig.SourceConfig || []).map((s) => s.key)
- );
- apiSiteEntries.forEach(([key, site]) => {
- if (!existed.has(key)) {
- adminConfig!.SourceConfig.push({
- key,
- name: site.name,
- api: site.api,
- detail: site.detail,
- from: 'config',
- disabled: false,
- });
- }
- });
-
- // 检查现有源是否在 fileConfig.api_site 中,如果不在则标记为 custom
- const apiSiteKeys = new Set(apiSiteEntries.map(([key]) => key));
- adminConfig.SourceConfig.forEach((source) => {
- if (!apiSiteKeys.has(source.key)) {
- source.from = 'custom';
- }
- });
-
- const existedUsers = new Set(
- (adminConfig.UserConfig.Users || []).map((u) => u.username)
- );
- userNames.forEach((uname) => {
- if (!existedUsers.has(uname)) {
- adminConfig!.UserConfig.Users.push({
- username: uname,
- role: 'user',
- });
- }
- });
- // 站长
- const ownerUser = process.env.USERNAME;
- if (ownerUser) {
- adminConfig!.UserConfig.Users =
- adminConfig!.UserConfig.Users.filter(
- (u) => u.username !== ownerUser
- );
- adminConfig!.UserConfig.Users.unshift({
- username: ownerUser,
- role: 'owner',
- });
- }
- } else {
- // 数据库中没有配置,创建新的管理员配置
- let allUsers = userNames.map((uname) => ({
- username: uname,
- role: 'user',
- }));
- const ownerUser = process.env.USERNAME;
- if (ownerUser) {
- allUsers = allUsers.filter((u) => u.username !== ownerUser);
- allUsers.unshift({
- username: ownerUser,
- role: 'owner',
- });
- }
- adminConfig = {
- SiteConfig: {
- SiteName: process.env.SITE_NAME || 'MoonTV',
- Announcement:
- process.env.ANNOUNCEMENT ||
- '本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
- SearchDownstreamMaxPage:
- Number(process.env.NEXT_PUBLIC_SEARCH_MAX_PAGE) || 5,
- SiteInterfaceCacheTime: fileConfig.cache_time || 7200,
- SearchResultDefaultAggregate:
- process.env.NEXT_PUBLIC_AGGREGATE_SEARCH_RESULT !== 'false',
- },
- UserConfig: {
- AllowRegister: process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true',
- Users: allUsers as any,
- },
- SourceConfig: apiSiteEntries.map(([key, site]) => ({
+ if (adminConfig) {
+ // 补全 SourceConfig
+ const existed = new Set(
+ (adminConfig.SourceConfig || []).map((s) => s.key)
+ );
+ apiSiteEntries.forEach(([key, site]) => {
+ if (!existed.has(key)) {
+ adminConfig!.SourceConfig.push({
key,
name: site.name,
api: site.api,
detail: site.detail,
from: 'config',
disabled: false,
- })),
- };
- }
+ });
+ }
+ });
- // 写回数据库(更新/创建)
- if (storage && typeof (storage as any).setAdminConfig === 'function') {
- await (storage as any).setAdminConfig(adminConfig);
- }
+ // 检查现有源是否在 fileConfig.api_site 中,如果不在则标记为 custom
+ const apiSiteKeys = new Set(apiSiteEntries.map(([key]) => key));
+ adminConfig.SourceConfig.forEach((source) => {
+ if (!apiSiteKeys.has(source.key)) {
+ source.from = 'custom';
+ }
+ });
- // 更新缓存
- cachedConfig = adminConfig;
- } catch (err) {
- console.error('加载管理员配置失败:', err);
+ const existedUsers = new Set(
+ (adminConfig.UserConfig.Users || []).map((u) => u.username)
+ );
+ userNames.forEach((uname) => {
+ if (!existedUsers.has(uname)) {
+ adminConfig!.UserConfig.Users.push({
+ username: uname,
+ role: 'user',
+ });
+ }
+ });
+ // 站长
+ const ownerUser = process.env.USERNAME;
+ if (ownerUser) {
+ adminConfig!.UserConfig.Users = adminConfig!.UserConfig.Users.filter(
+ (u) => u.username !== ownerUser
+ );
+ adminConfig!.UserConfig.Users.unshift({
+ username: ownerUser,
+ role: 'owner',
+ });
+ }
+ } else {
+ // 数据库中没有配置,创建新的管理员配置
+ let allUsers = userNames.map((uname) => ({
+ username: uname,
+ role: 'user',
+ }));
+ const ownerUser = process.env.USERNAME;
+ if (ownerUser) {
+ allUsers = allUsers.filter((u) => u.username !== ownerUser);
+ allUsers.unshift({
+ username: ownerUser,
+ role: 'owner',
+ });
+ }
+ adminConfig = {
+ SiteConfig: {
+ SiteName: process.env.SITE_NAME || 'MoonTV',
+ Announcement:
+ process.env.ANNOUNCEMENT ||
+ '本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
+ SearchDownstreamMaxPage:
+ Number(process.env.NEXT_PUBLIC_SEARCH_MAX_PAGE) || 5,
+ SiteInterfaceCacheTime: fileConfig.cache_time || 7200,
+ SearchResultDefaultAggregate:
+ process.env.NEXT_PUBLIC_AGGREGATE_SEARCH_RESULT !== 'false',
+ },
+ UserConfig: {
+ AllowRegister: process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true',
+ Users: allUsers as any,
+ },
+ SourceConfig: apiSiteEntries.map(([key, site]) => ({
+ key,
+ name: site.name,
+ api: site.api,
+ detail: site.detail,
+ from: 'config',
+ disabled: false,
+ })),
+ };
}
- })();
+
+ // 写回数据库(更新/创建)
+ if (storage && typeof (storage as any).setAdminConfig === 'function') {
+ await (storage as any).setAdminConfig(adminConfig);
+ }
+
+ // 更新缓存
+ cachedConfig = adminConfig;
+ } catch (err) {
+ console.error('加载管理员配置失败:', err);
+ }
} else {
// 本地存储直接使用文件配置
cachedConfig = {
@@ -221,7 +219,32 @@ async function initConfig() {
}
export async function getConfig(): Promise {
- await initConfig();
+ const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage';
+ if (process.env.DOCKER_ENV === 'true' || storageType === 'localstorage') {
+ await initConfig();
+ return cachedConfig;
+ }
+ // 非 docker 环境且 DB 存储,直接读 db 配置
+ const storage = getStorage();
+ let adminConfig: AdminConfig | null = null;
+ if (storage && typeof (storage as any).getAdminConfig === 'function') {
+ adminConfig = await (storage as any).getAdminConfig();
+ }
+ if (adminConfig) {
+ // 合并一些环境变量配置
+ adminConfig.SiteConfig.SiteName = process.env.SITE_NAME || 'MoonTV';
+ adminConfig.SiteConfig.Announcement =
+ process.env.ANNOUNCEMENT ||
+ '本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
+ adminConfig.UserConfig.AllowRegister =
+ process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true';
+ adminConfig.SiteConfig.SearchResultDefaultAggregate =
+ process.env.NEXT_PUBLIC_AGGREGATE_SEARCH_RESULT !== 'false';
+ cachedConfig = adminConfig;
+ } else {
+ // DB 无配置,执行一次初始化
+ await initConfig();
+ }
return cachedConfig;
}
diff --git a/src/lib/d1.db.ts b/src/lib/d1.db.ts
index ca2ecf7..87f487a 100644
--- a/src/lib/d1.db.ts
+++ b/src/lib/d1.db.ts
@@ -37,83 +37,6 @@ interface D1ExecResult {
duration: number;
}
-// 数据库初始化 SQL
-const INIT_SQL = `
- CREATE TABLE IF NOT EXISTS users (
- username TEXT PRIMARY KEY,
- password TEXT NOT NULL,
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
- );
-
- CREATE TABLE IF NOT EXISTS play_records (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- username TEXT NOT NULL,
- key TEXT NOT NULL,
- title TEXT NOT NULL,
- source_name TEXT NOT NULL,
- cover TEXT NOT NULL,
- year TEXT NOT NULL,
- index_episode INTEGER NOT NULL,
- total_episodes INTEGER NOT NULL,
- play_time INTEGER NOT NULL,
- total_time INTEGER NOT NULL,
- save_time INTEGER NOT NULL,
- search_title TEXT,
- UNIQUE(username, key)
- );
-
- CREATE TABLE IF NOT EXISTS favorites (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- username TEXT NOT NULL,
- key TEXT NOT NULL,
- title TEXT NOT NULL,
- source_name TEXT NOT NULL,
- cover TEXT NOT NULL,
- year TEXT NOT NULL,
- total_episodes INTEGER NOT NULL,
- save_time INTEGER NOT NULL,
- UNIQUE(username, key)
- );
-
- CREATE TABLE IF NOT EXISTS search_history (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- username TEXT NOT NULL,
- keyword TEXT NOT NULL,
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
- UNIQUE(username, keyword)
- );
-
- CREATE TABLE IF NOT EXISTS admin_config (
- id INTEGER PRIMARY KEY DEFAULT 1,
- config TEXT NOT NULL,
- updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
- );
-
- -- 基本索引
- CREATE INDEX IF NOT EXISTS idx_play_records_username ON play_records(username);
- CREATE INDEX IF NOT EXISTS idx_favorites_username ON favorites(username);
- CREATE INDEX IF NOT EXISTS idx_search_history_username ON search_history(username);
-
- -- 复合索引优化查询性能
- -- 播放记录:用户名+键值的复合索引,用于快速查找特定记录
- CREATE INDEX IF NOT EXISTS idx_play_records_username_key ON play_records(username, key);
- -- 播放记录:用户名+保存时间的复合索引,用于按时间排序的查询
- CREATE INDEX IF NOT EXISTS idx_play_records_username_save_time ON play_records(username, save_time DESC);
-
- -- 收藏:用户名+键值的复合索引,用于快速查找特定收藏
- CREATE INDEX IF NOT EXISTS idx_favorites_username_key ON favorites(username, key);
- -- 收藏:用户名+保存时间的复合索引,用于按时间排序的查询
- CREATE INDEX IF NOT EXISTS idx_favorites_username_save_time ON favorites(username, save_time DESC);
-
- -- 搜索历史:用户名+关键词的复合索引,用于快速查找/删除特定搜索记录
- CREATE INDEX IF NOT EXISTS idx_search_history_username_keyword ON search_history(username, keyword);
- -- 搜索历史:用户名+创建时间的复合索引,用于按时间排序的查询
- CREATE INDEX IF NOT EXISTS idx_search_history_username_created_at ON search_history(username, created_at DESC);
-
- -- 搜索历史清理查询的优化索引
- CREATE INDEX IF NOT EXISTS idx_search_history_username_id_created_at ON search_history(username, id, created_at DESC);
-`;
-
// 获取全局D1数据库实例
function getD1Database(): D1Database {
return (process.env as any).DB as D1Database;
@@ -121,30 +44,14 @@ function getD1Database(): D1Database {
export class D1Storage implements IStorage {
private db: D1Database | null = null;
- private initialized = false;
private async getDatabase(): Promise {
if (!this.db) {
this.db = getD1Database();
- if (!this.initialized) {
- await this.initDatabase();
- this.initialized = true;
- }
}
return this.db;
}
- private async initDatabase() {
- try {
- if (this.db) {
- await this.db.exec(INIT_SQL);
- }
- } catch (err) {
- console.error('Failed to initialize D1 database:', err);
- throw err;
- }
- }
-
// 播放记录相关
async getPlayRecord(
userName: string,
diff --git a/src/middleware.ts b/src/middleware.ts
index 9e96101..c8a8679 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -128,6 +128,6 @@ function shouldSkipAuth(pathname: string): boolean {
// 配置middleware匹配规则
export const config = {
matcher: [
- '/((?!_next/static|_next/image|favicon.ico|api/detail|api/search|api/image-proxy|api/douban).*)',
+ '/((?!_next/static|_next/image|favicon.ico|api/detail|api/search|api/image-proxy|api/douban|api/cron|api/server-config).*)',
],
};