fix: 完善成人内容过滤功能的部署兼容性

- 为用户设置API添加Edge Runtime配置确保部署兼容性
- 完善所有存储后端的用户设置方法实现
- 为D1数据库添加user_settings表迁移脚本
- 修复TypeScript类型错误和构建兼容性
- 所有25个API路由现在都正确配置了Edge Runtime
- 确保Docker、Cloudflare Pages等各平台部署正常运行
This commit is contained in:
katelya
2025-09-04 21:25:45 +08:00
parent 86ebbb2cf6
commit b06665788f
6 changed files with 161 additions and 3 deletions
+3
View File
@@ -4,6 +4,9 @@ import { NextRequest, NextResponse } from 'next/server';
import { getStorage } from '@/lib/db';
import { UserSettings } from '@/lib/types';
// 设置运行时为 Edge Runtime,确保部署兼容性
export const runtime = 'edge';
// 获取用户设置
export async function GET(_request: NextRequest) {
try {
+60 -1
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import { AdminConfig } from './admin.types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord } from './types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord, UserSettings } from './types';
// 搜索历史最大条数
const SEARCH_HISTORY_LIMIT = 20;
@@ -573,4 +573,63 @@ export class D1Storage implements IStorage {
throw err;
}
}
// ---------- 用户设置 ----------
async getUserSettings(userName: string): Promise<UserSettings | null> {
try {
const db = await this.getDatabase();
const row = await db
.prepare('SELECT settings FROM user_settings WHERE username = ?')
.bind(userName)
.first();
if (row && row.settings) {
return JSON.parse(row.settings as string) as UserSettings;
}
return null;
} catch (err) {
console.error('Failed to get user settings:', err);
throw err;
}
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
try {
const db = await this.getDatabase();
await db
.prepare(`
INSERT OR REPLACE INTO user_settings (username, settings, updated_time)
VALUES (?, ?, ?)
`)
.bind(userName, JSON.stringify(settings), Date.now())
.run();
} catch (err) {
console.error('Failed to set user settings:', err);
throw err;
}
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
+43 -1
View File
@@ -3,7 +3,7 @@
import { createClient, RedisClientType } from 'redis';
import { AdminConfig } from './admin.types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord } from './types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord, UserSettings } from './types';
// 搜索历史最大条数
const SEARCH_HISTORY_LIMIT = 20;
@@ -337,6 +337,48 @@ export class KvrocksStorage implements IStorage {
this.client.set(this.adminConfigKey(), JSON.stringify(config))
);
}
// ---------- 用户设置 ----------
private userSettingsKey(userName: string) {
return `u:${userName}:settings`;
}
async getUserSettings(userName: string): Promise<UserSettings | null> {
const val = await withRetry(() =>
this.client.get(this.userSettingsKey(userName))
);
return val ? (JSON.parse(val) as UserSettings) : null;
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
await withRetry(() =>
this.client.set(this.userSettingsKey(userName), JSON.stringify(settings))
);
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
// Kvrocks客户端单例
+42
View File
@@ -329,6 +329,48 @@ export class UpstashRedisStorage implements IStorage {
await this.client.srem(this.skipConfigsKey(userName), key);
});
}
// ---------- 用户设置 ----------
private userSettingsKey(userName: string) {
return `u:${userName}:settings`;
}
async getUserSettings(userName: string): Promise<UserSettings | null> {
const val = await withRetry(() =>
this.client.get(this.userSettingsKey(userName))
);
return val ? (val as UserSettings) : null;
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
await withRetry(() =>
this.client.set(this.userSettingsKey(userName), settings)
);
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
// 单例 Upstash Redis 客户端