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;
disabled?: boolean;
from: 'config' | 'custom';
is_adult?: boolean; // 添加成人内容标记字段
}
// 可折叠标签组件
@@ -643,6 +644,7 @@ const VideoSourceConfig = ({
detail: '',
disabled: false,
from: 'config',
is_adult: false, // 默认不是成人内容
});
// dnd-kit 传感器
@@ -721,6 +723,7 @@ const VideoSourceConfig = ({
name: newSource.name,
api: newSource.api,
detail: newSource.detail,
is_adult: newSource.is_adult, // 传递成人内容标记
})
.then(() => {
setNewSource({
@@ -730,6 +733,7 @@ const VideoSourceConfig = ({
detail: '',
disabled: false,
from: 'custom',
is_adult: false, // 重置为默认值
});
setShowAddForm(false);
})
@@ -866,7 +870,8 @@ const VideoSourceConfig = ({
exportConfig.api_site[source.key] = {
api: source.api,
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}: 无效的配置对象`);
}
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) {
throw new Error(`${key}: 缺少必要字段 api 或 name`);
@@ -950,7 +955,8 @@ const VideoSourceConfig = ({
key: key,
name: sourceObj.name,
api: sourceObj.api,
detail: sourceObj.detail || ''
detail: sourceObj.detail || '',
is_adult: sourceObj.is_adult || false // 确保处理 is_adult 字段
});
successCount++;
} 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'
/>
{/* 成人内容标记复选框 */}
<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 className='flex justify-end'>
<button
+3 -1
View File
@@ -59,11 +59,12 @@ export async function POST(request: NextRequest) {
switch (action) {
case 'add': {
const { key, name, api, detail } = body as {
const { key, name, api, detail, is_adult } = body as {
key?: string;
name?: string;
api?: string;
detail?: string;
is_adult?: boolean;
};
if (!key || !name || !api) {
return NextResponse.json({ error: '缺少必要参数' }, { status: 400 });
@@ -78,6 +79,7 @@ export async function POST(request: NextRequest) {
detail,
from: 'custom',
disabled: false,
is_adult: is_adult || false, // 确保处理 is_adult 字段
});
break;
}
+30 -2
View File
@@ -262,6 +262,7 @@ export async function getConfig(): Promise<AdminConfig> {
detail: site.detail,
from: 'config',
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) => {
if (!apiSiteKeys.has(source.key)) {
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[]> {
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) {
@@ -406,8 +426,16 @@ export async function getAvailableApiSites(filterAdult = false): Promise<ApiSite
// 获取成人内容资源站
export async function getAdultApiSites(): Promise<ApiSite[]> {
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
.filter((s) => !s.disabled && s.is_adult);
.filter((s) => !s.disabled && s.is_adult === true); // 只有明确为 true 的才被认为是成人内容
return adultSites.map((s) => ({
key: s.key,