首页增加短剧推荐
This commit is contained in:
@@ -262,6 +262,26 @@ export class DbManager {
|
||||
throw new Error('存储类型不支持清空数据操作');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 通用键值存储 ----------
|
||||
async getGlobalValue(key: string): Promise<string | null> {
|
||||
if (typeof (this.storage as any).getGlobalValue === 'function') {
|
||||
return (this.storage as any).getGlobalValue(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async setGlobalValue(key: string, value: string): Promise<void> {
|
||||
if (typeof (this.storage as any).setGlobalValue === 'function') {
|
||||
await (this.storage as any).setGlobalValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteGlobalValue(key: string): Promise<void> {
|
||||
if (typeof (this.storage as any).deleteGlobalValue === 'function') {
|
||||
await (this.storage as any).deleteGlobalValue(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出默认实例
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,no-console */
|
||||
|
||||
import { API_CONFIG, getAvailableApiSites } from '@/lib/config';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
interface CmsClassResponse {
|
||||
class?: Array<{
|
||||
type_id: string | number;
|
||||
type_name: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface DuanjuSource {
|
||||
key: string;
|
||||
name: string;
|
||||
api: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包含短剧分类的视频源列表
|
||||
*/
|
||||
export async function getDuanjuSources(): Promise<DuanjuSource[]> {
|
||||
try {
|
||||
// 先查询数据库中是否有缓存
|
||||
const cachedData = await db.getGlobalValue('duanju');
|
||||
|
||||
if (cachedData !== null) {
|
||||
// 有缓存,直接返回
|
||||
return cachedData ? JSON.parse(cachedData) : [];
|
||||
}
|
||||
|
||||
// 没有缓存,开始筛选
|
||||
console.log('开始筛选包含短剧分类的视频源...');
|
||||
const allSources = await getAvailableApiSites();
|
||||
const duanjuSources: DuanjuSource[] = [];
|
||||
|
||||
// 并发���求所有视频源的分类列表
|
||||
const checkPromises = allSources.map(async (source) => {
|
||||
try {
|
||||
const classUrl = `${source.api}?ac=list`;
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
||||
|
||||
const response = await fetch(classUrl, {
|
||||
headers: API_CONFIG.search.headers,
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data: CmsClassResponse = await response.json();
|
||||
|
||||
// 检查是否有短剧分类
|
||||
if (data.class && Array.isArray(data.class)) {
|
||||
const hasDuanju = data.class.some((item) => {
|
||||
const typeName = item.type_name?.toLowerCase() || '';
|
||||
return (
|
||||
typeName.includes('短剧') ||
|
||||
typeName.includes('短视频') ||
|
||||
typeName.includes('微短剧')
|
||||
);
|
||||
});
|
||||
|
||||
if (hasDuanju) {
|
||||
return {
|
||||
key: source.key,
|
||||
name: source.name,
|
||||
api: source.api,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
// 请求失败或超时,忽略该源
|
||||
console.error(`检查视频源 ${source.name} 失败:`, error);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const results = await Promise.all(checkPromises);
|
||||
|
||||
// 过滤掉null值
|
||||
results.forEach((result) => {
|
||||
if (result) {
|
||||
duanjuSources.push(result);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`找到 ${duanjuSources.length} 个包含短剧分类的视频源`);
|
||||
|
||||
// 存入数据库(即使是空数组也要存)
|
||||
await db.setGlobalValue('duanju', JSON.stringify(duanjuSources));
|
||||
|
||||
return duanjuSources;
|
||||
} catch (error) {
|
||||
console.error('获取短剧视频源失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -495,4 +495,26 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
throw new Error('清空数据失败');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 通用键值存储 ----------
|
||||
private globalValueKey(key: string) {
|
||||
return `global:${key}`;
|
||||
}
|
||||
|
||||
async getGlobalValue(key: string): Promise<string | null> {
|
||||
const val = await this.withRetry(() =>
|
||||
this.client.get(this.globalValueKey(key))
|
||||
);
|
||||
return val ? ensureString(val) : null;
|
||||
}
|
||||
|
||||
async setGlobalValue(key: string, value: string): Promise<void> {
|
||||
await this.withRetry(() =>
|
||||
this.client.set(this.globalValueKey(key), ensureString(value))
|
||||
);
|
||||
}
|
||||
|
||||
async deleteGlobalValue(key: string): Promise<void> {
|
||||
await this.withRetry(() => this.client.del(this.globalValueKey(key)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ export interface IStorage {
|
||||
|
||||
// 数据清理相关
|
||||
clearAllData(): Promise<void>;
|
||||
|
||||
// 通用键值存储
|
||||
getGlobalValue(key: string): Promise<string | null>;
|
||||
setGlobalValue(key: string, value: string): Promise<void>;
|
||||
deleteGlobalValue(key: string): Promise<void>;
|
||||
}
|
||||
|
||||
// 搜索结果数据结构
|
||||
|
||||
@@ -393,6 +393,28 @@ export class UpstashRedisStorage implements IStorage {
|
||||
throw new Error('清空数据失败');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 通用键值存储 ----------
|
||||
private globalValueKey(key: string) {
|
||||
return `global:${key}`;
|
||||
}
|
||||
|
||||
async getGlobalValue(key: string): Promise<string | null> {
|
||||
const val = await withRetry(() =>
|
||||
this.client.get(this.globalValueKey(key))
|
||||
);
|
||||
return val ? ensureString(val) : null;
|
||||
}
|
||||
|
||||
async setGlobalValue(key: string, value: string): Promise<void> {
|
||||
await withRetry(() =>
|
||||
this.client.set(this.globalValueKey(key), ensureString(value))
|
||||
);
|
||||
}
|
||||
|
||||
async deleteGlobalValue(key: string): Promise<void> {
|
||||
await withRetry(() => this.client.del(this.globalValueKey(key)));
|
||||
}
|
||||
}
|
||||
|
||||
// 单例 Upstash Redis 客户端
|
||||
|
||||
Reference in New Issue
Block a user