feat: 添加 is_adult 字段以支持成人内容标记,更新相关逻辑处理

This commit is contained in:
katelya
2025-09-05 00:57:57 +08:00
parent 24e9dd9b5d
commit 0e8ea7003a
3 changed files with 61 additions and 6 deletions
+28 -3
View File
@@ -70,6 +70,7 @@ interface DataSource {
detail?: string; detail?: string;
disabled?: boolean; disabled?: boolean;
from: 'config' | 'custom'; from: 'config' | 'custom';
is_adult?: boolean; // 添加成人内容标记字段
} }
// 可折叠标签组件 // 可折叠标签组件
@@ -643,6 +644,7 @@ const VideoSourceConfig = ({
detail: '', detail: '',
disabled: false, disabled: false,
from: 'config', from: 'config',
is_adult: false, // 默认不是成人内容
}); });
// dnd-kit 传感器 // dnd-kit 传感器
@@ -721,6 +723,7 @@ const VideoSourceConfig = ({
name: newSource.name, name: newSource.name,
api: newSource.api, api: newSource.api,
detail: newSource.detail, detail: newSource.detail,
is_adult: newSource.is_adult, // 传递成人内容标记
}) })
.then(() => { .then(() => {
setNewSource({ setNewSource({
@@ -730,6 +733,7 @@ const VideoSourceConfig = ({
detail: '', detail: '',
disabled: false, disabled: false,
from: 'custom', from: 'custom',
is_adult: false, // 重置为默认值
}); });
setShowAddForm(false); setShowAddForm(false);
}) })
@@ -866,7 +870,8 @@ const VideoSourceConfig = ({
exportConfig.api_site[source.key] = { exportConfig.api_site[source.key] = {
api: source.api, api: source.api,
name: source.name, name: source.name,
...(source.detail && { detail: source.detail }) ...(source.detail && { detail: source.detail }),
...(source.is_adult !== undefined && { is_adult: source.is_adult }) // 确保导出 is_adult 字段
}; };
} }
}); });
@@ -939,7 +944,7 @@ const VideoSourceConfig = ({
throw new Error(`${key}: 无效的配置对象`); throw new Error(`${key}: 无效的配置对象`);
} }
const sourceObj = source as { api?: string; name?: string; detail?: string }; const sourceObj = source as { api?: string; name?: string; detail?: string; is_adult?: boolean };
if (!sourceObj.api || !sourceObj.name) { if (!sourceObj.api || !sourceObj.name) {
throw new Error(`${key}: 缺少必要字段 api 或 name`); throw new Error(`${key}: 缺少必要字段 api 或 name`);
@@ -950,7 +955,8 @@ const VideoSourceConfig = ({
key: key, key: key,
name: sourceObj.name, name: sourceObj.name,
api: sourceObj.api, api: sourceObj.api,
detail: sourceObj.detail || '' detail: sourceObj.detail || '',
is_adult: sourceObj.is_adult || false // 确保处理 is_adult 字段
}); });
successCount++; successCount++;
} catch (error) { } catch (error) {
@@ -1246,6 +1252,25 @@ const VideoSourceConfig = ({
} }
className='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' className='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'
/> />
{/* 成人内容标记复选框 */}
<div className='flex items-center space-x-2'>
<input
type='checkbox'
id='is_adult'
checked={newSource.is_adult || false}
onChange={(e) =>
setNewSource((prev) => ({ ...prev, is_adult: e.target.checked }))
}
className='w-4 h-4 text-red-600 bg-gray-100 border-gray-300 rounded focus:ring-red-500 dark:bg-gray-700 dark:border-gray-600'
/>
<label
htmlFor='is_adult'
className='text-sm font-medium text-gray-900 dark:text-gray-300'
>
🔞
</label>
</div>
</div> </div>
<div className='flex justify-end'> <div className='flex justify-end'>
<button <button
+3 -1
View File
@@ -59,11 +59,12 @@ export async function POST(request: NextRequest) {
switch (action) { switch (action) {
case 'add': { case 'add': {
const { key, name, api, detail } = body as { const { key, name, api, detail, is_adult } = body as {
key?: string; key?: string;
name?: string; name?: string;
api?: string; api?: string;
detail?: string; detail?: string;
is_adult?: boolean;
}; };
if (!key || !name || !api) { if (!key || !name || !api) {
return NextResponse.json({ error: '缺少必要参数' }, { status: 400 }); return NextResponse.json({ error: '缺少必要参数' }, { status: 400 });
@@ -78,6 +79,7 @@ export async function POST(request: NextRequest) {
detail, detail,
from: 'custom', from: 'custom',
disabled: false, disabled: false,
is_adult: is_adult || false, // 确保处理 is_adult 字段
}); });
break; break;
} }
+30 -2
View File
@@ -262,6 +262,7 @@ export async function getConfig(): Promise<AdminConfig> {
detail: site.detail, detail: site.detail,
from: 'config', from: 'config',
disabled: false, disabled: false,
is_adult: (site as any).is_adult || false, // 确保处理 is_adult 字段
}); });
} }
}); });
@@ -271,6 +272,12 @@ export async function getConfig(): Promise<AdminConfig> {
adminConfig.SourceConfig.forEach((source) => { adminConfig.SourceConfig.forEach((source) => {
if (!apiSiteKeys.has(source.key)) { if (!apiSiteKeys.has(source.key)) {
source.from = 'custom'; source.from = 'custom';
} else {
// 更新现有源的 is_adult 字段
const siteConfig = fileConfig.api_site[source.key];
if (siteConfig) {
source.is_adult = (siteConfig as any).is_adult || false;
}
} }
}); });
@@ -388,7 +395,20 @@ export async function getCacheTime(): Promise<number> {
export async function getAvailableApiSites(filterAdult = false): Promise<ApiSite[]> { export async function getAvailableApiSites(filterAdult = false): Promise<ApiSite[]> {
const config = await getConfig(); const config = await getConfig();
let sites = config.SourceConfig.filter((s) => !s.disabled);
// 防御性检查:确保 SourceConfig 存在且为数组
if (!config.SourceConfig || !Array.isArray(config.SourceConfig)) {
console.warn('SourceConfig is missing or not an array, returning empty array');
return [];
}
// 防御性处理:为每个源确保 is_adult 字段存在
let sites = config.SourceConfig
.filter((s) => !s.disabled)
.map((s) => ({
...s,
is_adult: s.is_adult === true // 严格检查,只有明确为 true 的才是成人内容
}));
// 如果需要过滤成人内容,则排除标记为成人内容的资源站 // 如果需要过滤成人内容,则排除标记为成人内容的资源站
if (filterAdult) { if (filterAdult) {
@@ -406,8 +426,16 @@ export async function getAvailableApiSites(filterAdult = false): Promise<ApiSite
// 获取成人内容资源站 // 获取成人内容资源站
export async function getAdultApiSites(): Promise<ApiSite[]> { export async function getAdultApiSites(): Promise<ApiSite[]> {
const config = await getConfig(); const config = await getConfig();
// 防御性检查:确保 SourceConfig 存在且为数组
if (!config.SourceConfig || !Array.isArray(config.SourceConfig)) {
console.warn('SourceConfig is missing or not an array, returning empty array');
return [];
}
// 防御性处理:严格检查成人内容标记
const adultSites = config.SourceConfig const adultSites = config.SourceConfig
.filter((s) => !s.disabled && s.is_adult); .filter((s) => !s.disabled && s.is_adult === true); // 只有明确为 true 的才被认为是成人内容
return adultSites.map((s) => ({ return adultSites.map((s) => ({
key: s.key, key: s.key,