From c484dde326ad868121e0e0e1b773bd8a801d2635 Mon Sep 17 00:00:00 2001 From: katelya Date: Fri, 5 Sep 2025 01:30:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4=20config.json=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=20API=20=E6=BA=90=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=A4=BA=E4=BE=8B=E9=85=8D=E7=BD=AE=E4=BB=A5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=88=90=E4=BA=BA=E5=86=85=E5=AE=B9=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ADULT_CONTENT_FILTER_TEST.md | 83 ++++++++++++++++++++++++++++++++++++ VIDEO_SOURCE_CONFIG.md | 44 +++++++++++++++++++ config.example.json | 29 +++++++++++++ config.json | 27 +----------- src/app/api/search/route.ts | 23 ++++++---- 5 files changed, 171 insertions(+), 35 deletions(-) create mode 100644 ADULT_CONTENT_FILTER_TEST.md create mode 100644 VIDEO_SOURCE_CONFIG.md create mode 100644 config.example.json diff --git a/ADULT_CONTENT_FILTER_TEST.md b/ADULT_CONTENT_FILTER_TEST.md new file mode 100644 index 0000000..bea2c9e --- /dev/null +++ b/ADULT_CONTENT_FILTER_TEST.md @@ -0,0 +1,83 @@ +# 成人内容过滤功能验证指南 + +## 🔒 过滤功能说明 + +### 工作原理 +1. **默认行为**:所有用户默认开启成人内容过滤 +2. **源级别标记**:每个视频源都有 `is_adult` 标记 +3. **用户设置**:用户可通过设置页面控制过滤开关 +4. **API级别分离**:搜索API将结果分为 `regular_results` 和 `adult_results` + +### 过滤逻辑 +```typescript +// 1. 获取用户设置 +shouldFilterAdult = userSettings?.filter_adult_content !== false; // 默认true + +// 2. 源分离 +getAvailableApiSites() // 返回 is_adult: false 的源 +getAdultApiSites() // 返回 is_adult: true 的源 + +// 3. 搜索分离 +regular_results: [...] // 来自常规源 +adult_results: [...] // 来自成人源(仅在用户关闭过滤且明确请求时) +``` + +## 🧪 测试步骤 + +### 1. 添加测试源 +在管理后台添加以下测试源: + +**常规源:** +``` +源标识:test_regular +源名称:测试常规源 +API地址:https://okzy.tv/api.php/provide/vod +详情地址:https://okzy.tv/api.php/provide/vod/?ac=detail&ids={ids} +是否成人内容:❌ 否 +``` + +**成人内容源:** +``` +源标识:test_adult +源名称:测试成人源 +API地址:https://adult-test.com/api.php/provide/vod +详情地址:https://adult-test.com/api.php/provide/vod/?ac=detail&ids={ids} +是否成人内容:✅ 是 +``` + +### 2. 验证过滤开启状态 +- 访问用户设置页面,确认"成人内容过滤"开关为**开启** +- 搜索任意关键词,应该只返回常规源的结果 +- API响应中 `adult_results` 应为空数组 + +### 3. 验证过滤关闭状态 +- 关闭"成人内容过滤"开关 +- 搜索相同关键词 +- 应该看到结果分为两组:常规内容 + 成人内容 + +### 4. API级别验证 +```bash +# 开启过滤(默认) +curl "http://localhost:3001/api/search?q=test" +# 预期:adult_results = [] + +# 关闭过滤且明确请求成人内容 +curl "http://localhost:3001/api/search?q=test&include_adult=true" -H "Authorization: Bearer username" +# 预期:adult_results 包含成人源结果 +``` + +## ✅ 验证要点 + +1. **默认保护**:新用户默认开启过滤 +2. **源级别隔离**:is_adult 标记正确分离源 +3. **用户可控**:设置页面可以切换过滤状态 +4. **API响应分离**:结果明确分组 +5. **明确请求**:关闭过滤后需明确请求成人内容才返回 + +## 🚨 安全检查 + +- [ ] 默认开启过滤 +- [ ] 设置页面有明确的年龄警告 +- [ ] API不会意外返回成人内容 +- [ ] 源标记 `is_adult: true` 的源被正确隔离 +- [ ] 前端正确处理分组结果 diff --git a/VIDEO_SOURCE_CONFIG.md b/VIDEO_SOURCE_CONFIG.md new file mode 100644 index 0000000..10f34b5 --- /dev/null +++ b/VIDEO_SOURCE_CONFIG.md @@ -0,0 +1,44 @@ +# 视频源配置说明 + +## 配置方式 + +您有两种方式配置视频源: + +### 方式 1:通过管理后台配置(推荐) + +1. 访问 `/admin` 管理后台 +2. 在"源管理"部分添加视频源 +3. 支持实时启用/禁用 +4. 数据保存在数据库中,重启不丢失 + +### 方式 2:通过 config.json 配置 + +参考 `config.example.json` 文件的格式: + +```json +{ + "cache_time": 7200, + "api_site": { + "source_key": { + "api": "https://your-api.com/api.php/provide/vod", + "name": "源名称", + "detail": "https://your-api.com/api.php/provide/vod/?ac=detail&ids={ids}", + "is_adult": false + } + } +} +``` + +## 字段说明 + +- `source_key`: 源的唯一标识符 +- `api`: 视频 API 的搜索接口地址 +- `name`: 源的显示名称 +- `detail`: 视频详情接口地址({ids} 会被替换为视频 ID) +- `is_adult`: 是否为成人内容源(true/false) + +## 推荐设置 + +- 建议保持 `config.json` 为空配置:`{"cache_time": 7200, "api_site": {}}` +- 通过管理后台动态添加和管理视频源 +- 这样更灵活,支持实时启用/禁用,无需重启服务 diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..32c6a5e --- /dev/null +++ b/config.example.json @@ -0,0 +1,29 @@ +{ + "cache_time": 7200, + "api_site": { + "example_source": { + "api": "https://your-video-api.com/api.php/provide/vod", + "name": "示例视频源", + "detail": "https://your-video-api.com/api.php/provide/vod/?ac=detail&ids={ids}", + "is_adult": false + }, + "another_example": { + "api": "https://another-api.com/api.php/provide/vod", + "name": "另一个示例源", + "detail": "https://another-api.com/api.php/provide/vod/?ac=detail&ids={ids}", + "is_adult": false + }, + "adult_example": { + "api": "https://adult-content-api.com/api.php/provide/vod", + "name": "成人内容源示例", + "detail": "https://adult-content-api.com/api.php/provide/vod/?ac=detail&ids={ids}", + "is_adult": true + }, + "test_adult_source": { + "api": "https://test-adult-api.com/api.php/provide/vod", + "name": "测试成人源(用于验证过滤)", + "detail": "https://test-adult-api.com/api.php/provide/vod/?ac=detail&ids={ids}", + "is_adult": true + } + } +} diff --git a/config.json b/config.json index 65d5b5c..dd7aff1 100644 --- a/config.json +++ b/config.json @@ -1,29 +1,4 @@ { "cache_time": 7200, - "api_site": { - "okzy": { - "api": "https://okzy.tv/api.php/provide/vod", - "name": "OK资源", - "detail": "https://okzy.tv/api.php/provide/vod/?ac=detail&ids={ids}", - "is_adult": false - }, - "hnzy": { - "api": "https://www.hongniuzy.com/inc/api.php", - "name": "红牛资源", - "detail": "https://www.hongniuzy.com/inc/api.php?ac=detail&ids={ids}", - "is_adult": false - }, - "ffzy": { - "api": "https://cj.ffzyapi.com/api.php/provide/vod", - "name": "非凡资源", - "detail": "https://cj.ffzyapi.com/api.php/provide/vod/?ac=detail&ids={ids}", - "is_adult": false - }, - "lzzy": { - "api": "https://api.lzapi.com/api.php/provide/vod", - "name": "量子资源", - "detail": "https://api.lzapi.com/api.php/provide/vod/?ac=detail&ids={ids}", - "is_adult": false - } - } + "api_site": {} } diff --git a/src/app/api/search/route.ts b/src/app/api/search/route.ts index 4ec1562..f813864 100644 --- a/src/app/api/search/route.ts +++ b/src/app/api/search/route.ts @@ -46,16 +46,21 @@ export async function GET(request: Request) { shouldFilterAdult = userSettings?.filter_adult_content !== false; } - // 获取常规资源站 - const regularSites = await getAvailableApiSites(true); // 总是过滤成人内容 - console.log('搜索API - 获取到的常规站点数量:', regularSites.length); - console.log('搜索API - 常规站点列表:', regularSites.map(s => s.name).join(', ')); - - const regularSearchPromises = regularSites.map((site) => searchFromApi(site, query)); - const regularResults = (await Promise.all(regularSearchPromises)).flat(); - console.log('搜索API - 常规搜索结果数量:', regularResults.length); + // 获取所有可用的API站点(不包含成人内容) + const regularSites = await getAvailableApiSites(); + + if (!regularSites || regularSites.length === 0) { + return Response.json({ + regular_results: [], + adult_results: [] + }); + } - let adultResults: unknown[] = []; + // 搜索常规(非成人)内容 + const regularSearchPromises = regularSites.map((site) => searchFromApi(site, query)); + const regularResults = (await Promise.all(regularSearchPromises)).flat(); + + let adultResults: unknown[] = []; // 如果用户设置允许且明确请求包含成人内容,则搜索成人资源站 if (!shouldFilterAdult && includeAdult) {