Files
MoonTVPlus/src/lib/config.ts

652 lines
20 KiB
TypeScript
Raw Normal View History

2025-08-12 21:50:58 +08:00
/* eslint-disable @typescript-eslint/no-explicit-any, no-console, @typescript-eslint/no-non-null-assertion */
import { db } from '@/lib/db';
2025-08-12 21:50:58 +08:00
import { AdminConfig } from './admin.types';
export interface ApiSite {
key: string;
api: string;
name: string;
detail?: string;
2025-12-28 21:01:49 +08:00
proxyMode?: boolean;
2025-08-12 21:50:58 +08:00
}
2025-08-24 00:26:48 +08:00
export interface LiveCfg {
name: string;
url: string;
ua?: string;
epg?: string; // 节目单
}
2025-08-12 21:50:58 +08:00
interface ConfigFileStruct {
cache_time?: number;
2025-08-13 00:30:31 +08:00
api_site?: {
2025-08-12 21:50:58 +08:00
[key: string]: ApiSite;
};
custom_category?: {
name?: string;
type: 'movie' | 'tv';
query: string;
}[];
2025-08-24 00:26:48 +08:00
lives?: {
[key: string]: LiveCfg;
}
2025-08-12 21:50:58 +08:00
}
export const API_CONFIG = {
search: {
path: '?ac=videolist&wd=',
pagePath: '?ac=videolist&wd={query}&pg={page}',
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
Accept: 'application/json',
},
},
detail: {
path: '?ac=videolist&ids=',
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
Accept: 'application/json',
},
},
};
// 在模块加载时根据环境决定配置来源
let cachedConfig: AdminConfig;
let configInitPromise: Promise<AdminConfig> | null = null;
2025-08-12 21:50:58 +08:00
2025-08-24 00:26:48 +08:00
2025-08-13 13:20:58 +08:00
// 从配置文件补充管理员配置
2025-08-13 00:30:31 +08:00
export function refineConfig(adminConfig: AdminConfig): AdminConfig {
2025-08-13 13:20:58 +08:00
let fileConfig: ConfigFileStruct;
2025-08-13 00:30:31 +08:00
try {
fileConfig = JSON.parse(adminConfig.ConfigFile) as ConfigFileStruct;
} catch (e) {
fileConfig = {} as ConfigFileStruct;
}
2025-08-13 13:20:58 +08:00
2025-08-13 00:30:31 +08:00
// 合并文件中的源信息
2025-08-13 13:20:58 +08:00
const apiSitesFromFile = Object.entries(fileConfig.api_site || []);
const currentApiSites = new Map(
2025-08-13 00:30:31 +08:00
(adminConfig.SourceConfig || []).map((s) => [s.key, s])
);
2025-08-13 13:20:58 +08:00
apiSitesFromFile.forEach(([key, site]) => {
const existingSource = currentApiSites.get(key);
2025-08-13 00:30:31 +08:00
if (existingSource) {
// 如果已存在,只覆盖 name、api、detail 和 from
existingSource.name = site.name;
existingSource.api = site.api;
existingSource.detail = site.detail;
existingSource.from = 'config';
} else {
// 如果不存在,创建新条目
2025-08-13 13:20:58 +08:00
currentApiSites.set(key, {
2025-08-13 00:30:31 +08:00
key,
name: site.name,
api: site.api,
detail: site.detail,
from: 'config',
disabled: false,
});
}
});
// 检查现有源是否在 fileConfig.api_site 中,如果不在则标记为 custom
2025-08-13 13:20:58 +08:00
const apiSitesFromFileKey = new Set(apiSitesFromFile.map(([key]) => key));
currentApiSites.forEach((source) => {
if (!apiSitesFromFileKey.has(source.key)) {
2025-08-13 00:30:31 +08:00
source.from = 'custom';
}
});
// 将 Map 转换回数组
2025-08-13 13:20:58 +08:00
adminConfig.SourceConfig = Array.from(currentApiSites.values());
2025-08-13 00:30:31 +08:00
// 覆盖 CustomCategories
2025-08-13 13:20:58 +08:00
const customCategoriesFromFile = fileConfig.custom_category || [];
const currentCustomCategories = new Map(
2025-08-13 00:30:31 +08:00
(adminConfig.CustomCategories || []).map((c) => [c.query + c.type, c])
);
2025-08-13 13:20:58 +08:00
customCategoriesFromFile.forEach((category) => {
2025-08-13 00:30:31 +08:00
const key = category.query + category.type;
2025-08-13 13:20:58 +08:00
const existedCategory = currentCustomCategories.get(key);
2025-08-13 00:30:31 +08:00
if (existedCategory) {
existedCategory.name = category.name;
existedCategory.query = category.query;
existedCategory.type = category.type;
existedCategory.from = 'config';
} else {
2025-08-13 13:20:58 +08:00
currentCustomCategories.set(key, {
2025-08-13 00:30:31 +08:00
name: category.name,
type: category.type,
query: category.query,
from: 'config',
disabled: false,
});
}
});
// 检查现有 CustomCategories 是否在 fileConfig.custom_category 中,如果不在则标记为 custom
2025-08-13 13:20:58 +08:00
const customCategoriesFromFileKeys = new Set(
customCategoriesFromFile.map((c) => c.query + c.type)
2025-08-13 00:30:31 +08:00
);
2025-08-13 13:20:58 +08:00
currentCustomCategories.forEach((category) => {
if (!customCategoriesFromFileKeys.has(category.query + category.type)) {
2025-08-13 00:30:31 +08:00
category.from = 'custom';
}
});
// 将 Map 转换回数组
2025-08-13 13:20:58 +08:00
adminConfig.CustomCategories = Array.from(currentCustomCategories.values());
2025-08-13 00:30:31 +08:00
2025-08-24 00:26:48 +08:00
const livesFromFile = Object.entries(fileConfig.lives || []);
const currentLives = new Map(
(adminConfig.LiveConfig || []).map((l) => [l.key, l])
);
livesFromFile.forEach(([key, site]) => {
const existingLive = currentLives.get(key);
if (existingLive) {
existingLive.name = site.name;
existingLive.url = site.url;
existingLive.ua = site.ua;
existingLive.epg = site.epg;
} else {
// 如果不存在,创建新条目
currentLives.set(key, {
key,
name: site.name,
url: site.url,
ua: site.ua,
epg: site.epg,
channelNumber: 0,
from: 'config',
disabled: false,
});
}
});
// 检查现有 LiveConfig 是否在 fileConfig.lives 中,如果不在则标记为 custom
const livesFromFileKeys = new Set(livesFromFile.map(([key]) => key));
currentLives.forEach((live) => {
if (!livesFromFileKeys.has(live.key)) {
live.from = 'custom';
}
});
// 将 Map 转换回数组
adminConfig.LiveConfig = Array.from(currentLives.values());
2025-08-13 00:30:31 +08:00
return adminConfig;
}
2025-08-13 13:20:58 +08:00
async function getInitConfig(configFile: string, subConfig: {
URL: string;
AutoUpdate: boolean;
LastCheck: string;
} = {
URL: "",
AutoUpdate: false,
LastCheck: "",
}): Promise<AdminConfig> {
let cfgFile: ConfigFileStruct;
2026-01-18 11:57:05 +08:00
// 优先从环境变量读取订阅 URL
const envSubUrl = process.env.CONFIG_SUBSCRIPTION_URL || "";
if (envSubUrl) {
try {
const response = await fetch(envSubUrl);
if (response.ok) {
const configContent = await response.text();
const bs58 = (await import('bs58')).default;
const decodedBytes = bs58.decode(configContent);
const decodedContent = new TextDecoder().decode(decodedBytes);
configFile = decodedContent;
console.log('已从订阅 URL 获取配置');
}
} catch (e) {
console.error('从订阅 URL 获取配置失败:', e);
}
}
// 优先从环境变量读取配置
const envConfig = process.env.INIT_CONFIG || "";
const configSource = envConfig || configFile;
2025-08-13 13:20:58 +08:00
try {
2026-01-18 11:57:05 +08:00
cfgFile = JSON.parse(configSource) as ConfigFileStruct;
2025-08-13 13:20:58 +08:00
} catch (e) {
cfgFile = {} as ConfigFileStruct;
2025-08-12 21:50:58 +08:00
}
2025-08-13 22:07:28 +08:00
const adminConfig: AdminConfig = {
2026-01-18 11:57:05 +08:00
ConfigFile: configSource,
2025-08-13 13:20:58 +08:00
ConfigSubscribtion: subConfig,
SiteConfig: {
2025-12-14 23:25:43 +08:00
SiteName: process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTVPlus',
2025-08-13 13:20:58 +08:00
Announcement:
process.env.ANNOUNCEMENT ||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
SearchDownstreamMaxPage:
Number(process.env.NEXT_PUBLIC_SEARCH_MAX_PAGE) || 5,
SiteInterfaceCacheTime: cfgFile.cache_time || 7200,
DoubanProxyType:
2025-08-26 22:53:04 +08:00
process.env.NEXT_PUBLIC_DOUBAN_PROXY_TYPE || 'cmliussss-cdn-tencent',
2025-08-13 13:20:58 +08:00
DoubanProxy: process.env.NEXT_PUBLIC_DOUBAN_PROXY || '',
DoubanImageProxyType:
2025-08-26 22:53:04 +08:00
process.env.NEXT_PUBLIC_DOUBAN_IMAGE_PROXY_TYPE || 'cmliussss-cdn-tencent',
2025-08-13 13:20:58 +08:00
DoubanImageProxy: process.env.NEXT_PUBLIC_DOUBAN_IMAGE_PROXY || '',
DisableYellowFilter:
process.env.NEXT_PUBLIC_DISABLE_YELLOW_FILTER === 'true',
2025-08-17 17:32:42 +08:00
FluidSearch:
process.env.NEXT_PUBLIC_FLUID_SEARCH !== 'false',
2025-12-02 01:00:42 +08:00
// 弹幕配置
DanmakuApiBase: process.env.DANMAKU_API_BASE || 'http://localhost:9321',
DanmakuApiToken: process.env.DANMAKU_API_TOKEN || '87654321',
2025-12-14 22:15:38 +08:00
// TMDB配置
2026-01-18 11:57:05 +08:00
TMDBApiKey: process.env.TMDB_API_KEY || '',
TMDBProxy: process.env.TMDB_PROXY || '',
TMDBReverseProxy: process.env.TMDB_REVERSE_PROXY || '',
2026-01-23 14:28:35 +08:00
// Pansou配置
PansouApiUrl: '',
PansouUsername: '',
PansouPassword: '',
PansouKeywordBlocklist: '',
// 评论功能开关
EnableComments: false,
2025-08-13 13:20:58 +08:00
},
UserConfig: {
Users: [],
},
SourceConfig: [],
CustomCategories: [],
2025-08-24 00:26:48 +08:00
LiveConfig: [],
2025-08-13 13:20:58 +08:00
};
2025-08-12 21:50:58 +08:00
2026-01-24 18:17:19 +08:00
// 用户信息已迁移到新版数据库,不再填充 UserConfig.Users
// 保持为空数组,避免与新版用户系统冲突
adminConfig.UserConfig.Users = [];
2025-08-12 21:50:58 +08:00
2025-08-13 13:20:58 +08:00
// 从配置文件中补充源信息
Object.entries(cfgFile.api_site || []).forEach(([key, site]) => {
adminConfig.SourceConfig.push({
key: key,
name: site.name,
api: site.api,
detail: site.detail,
from: 'config',
disabled: false,
});
});
2025-08-12 21:50:58 +08:00
2025-08-13 13:20:58 +08:00
// 从配置文件中补充自定义分类信息
cfgFile.custom_category?.forEach((category) => {
adminConfig.CustomCategories.push({
name: category.name || category.query,
type: category.type,
query: category.query,
from: 'config',
disabled: false,
});
});
2025-08-13 00:30:31 +08:00
2025-08-24 00:26:48 +08:00
// 从配置文件中补充直播源信息
Object.entries(cfgFile.lives || []).forEach(([key, live]) => {
if (!adminConfig.LiveConfig) {
adminConfig.LiveConfig = [];
}
adminConfig.LiveConfig.push({
key,
name: live.name,
url: live.url,
ua: live.ua,
epg: live.epg,
channelNumber: 0,
from: 'config',
disabled: false,
});
});
2025-08-13 13:20:58 +08:00
return adminConfig;
2025-08-12 21:50:58 +08:00
}
export async function getConfig(): Promise<AdminConfig> {
2025-08-13 13:20:58 +08:00
// 直接使用内存缓存
if (cachedConfig) {
2025-08-12 21:50:58 +08:00
return cachedConfig;
}
2025-08-13 13:20:58 +08:00
// 如果正在初始化,等待初始化完成
if (configInitPromise) {
return configInitPromise;
2025-08-12 21:50:58 +08:00
}
// 创建初始化 Promise
configInitPromise = (async () => {
2026-01-18 11:57:05 +08:00
const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage';
// localStorage 模式下直接从环境变量初始化
if (storageType === 'localstorage') {
console.log('localStorage 模式:从环境变量初始化配置');
const adminConfig = await getInitConfig("");
cachedConfig = configSelfCheck(adminConfig);
configInitPromise = null;
return cachedConfig;
}
// 读 db
let adminConfig: AdminConfig | null = null;
let dbReadFailed = false;
try {
adminConfig = await db.getAdminConfig();
} catch (e) {
console.error('获取管理员配置失败:', e);
dbReadFailed = true;
2025-12-14 23:43:06 +08:00
}
2025-12-24 00:42:28 +08:00
// db 中无配置,执行一次初始化
if (!adminConfig) {
if (dbReadFailed) {
// 数据库读取失败,使用默认配置但不保存,避免覆盖数据库
console.warn('数据库读取失败,使用临时默认配置(不会保存到数据库)');
adminConfig = await getInitConfig("");
} else {
// 数据库中确实没有配置,首次初始化并保存
console.log('首次初始化配置');
adminConfig = await getInitConfig("");
2025-12-24 00:42:28 +08:00
await db.saveAdminConfig(adminConfig);
}
}
2026-01-08 00:14:07 +08:00
// 检查是否有旧格式Emby配置需要迁移
const needsEmbyMigration = adminConfig.EmbyConfig &&
adminConfig.EmbyConfig.ServerURL &&
!adminConfig.EmbyConfig.Sources;
adminConfig = configSelfCheck(adminConfig);
cachedConfig = adminConfig;
2026-01-08 00:14:07 +08:00
// 如果进行了Emby配置迁移保存到数据库
if (!dbReadFailed && needsEmbyMigration) {
try {
await db.saveAdminConfig(adminConfig);
console.log('[Config] Emby配置迁移已保存到数据库');
} catch (error) {
console.error('[Config] 保存迁移后的配置失败:', error);
}
}
// 自动迁移用户如果配置中有用户且V2存储支持
// 过滤掉站长后检查是否有需要迁移的用户
const nonOwnerUsers = adminConfig.UserConfig.Users.filter(
(u) => u.username !== process.env.USERNAME
);
if (!dbReadFailed && nonOwnerUsers.length > 0) {
try {
// 检查是否支持V2存储
const storage = (db as any).storage;
if (storage && typeof storage.createUserV2 === 'function') {
console.log('检测到配置中有用户,开始自动迁移...');
await db.migrateUsersFromConfig(adminConfig);
// 迁移完成后,清空配置中的用户列表并保存
adminConfig.UserConfig.Users = [];
await db.saveAdminConfig(adminConfig);
cachedConfig = adminConfig;
console.log('用户自动迁移完成');
}
} catch (error) {
console.error('自动迁移用户失败:', error);
// 不影响主流程,继续执行
}
}
// 清除初始化 Promise
configInitPromise = null;
return cachedConfig;
})();
2025-12-24 00:42:28 +08:00
return configInitPromise;
2025-08-12 21:50:58 +08:00
}
2025-08-15 22:34:26 +08:00
export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
2025-08-15 22:44:19 +08:00
// 确保必要的属性存在和初始化
2025-12-02 01:00:42 +08:00
if (!adminConfig.SiteConfig) {
adminConfig.SiteConfig = {
2025-12-14 23:25:43 +08:00
SiteName: 'MoonTVPlus',
2025-12-02 01:00:42 +08:00
Announcement: '',
SearchDownstreamMaxPage: 5,
SiteInterfaceCacheTime: 7200,
DoubanProxyType: 'cmliussss-cdn-tencent',
DoubanProxy: '',
DoubanImageProxyType: 'cmliussss-cdn-tencent',
DoubanImageProxy: '',
DisableYellowFilter: false,
FluidSearch: true,
DanmakuApiBase: 'http://localhost:9321',
DanmakuApiToken: '87654321',
2026-01-23 14:28:35 +08:00
PansouApiUrl: '',
PansouUsername: '',
PansouPassword: '',
PansouKeywordBlocklist: '',
EnableComments: false,
2025-12-02 01:00:42 +08:00
};
}
// 确保弹幕配置存在
if (!adminConfig.SiteConfig.DanmakuApiBase) {
adminConfig.SiteConfig.DanmakuApiBase = 'http://localhost:9321';
}
if (!adminConfig.SiteConfig.DanmakuApiToken) {
adminConfig.SiteConfig.DanmakuApiToken = '87654321';
}
// 确保评论开关存在
if (adminConfig.SiteConfig.EnableComments === undefined) {
adminConfig.SiteConfig.EnableComments = false;
}
2026-01-23 14:28:35 +08:00
if (adminConfig.SiteConfig.PansouKeywordBlocklist === undefined) {
adminConfig.SiteConfig.PansouKeywordBlocklist = '';
}
2025-08-15 22:44:19 +08:00
if (!adminConfig.UserConfig) {
2025-08-18 23:15:37 +08:00
adminConfig.UserConfig = { Users: [] };
2025-08-15 22:44:19 +08:00
}
if (!adminConfig.UserConfig.Users || !Array.isArray(adminConfig.UserConfig.Users)) {
adminConfig.UserConfig.Users = [];
}
if (!adminConfig.SourceConfig || !Array.isArray(adminConfig.SourceConfig)) {
adminConfig.SourceConfig = [];
}
if (!adminConfig.CustomCategories || !Array.isArray(adminConfig.CustomCategories)) {
adminConfig.CustomCategories = [];
}
2025-08-24 00:26:48 +08:00
if (!adminConfig.LiveConfig || !Array.isArray(adminConfig.LiveConfig)) {
adminConfig.LiveConfig = [];
}
2025-08-15 22:44:19 +08:00
2026-01-24 18:17:19 +08:00
// 用户信息已迁移到新版数据库
// 这里只保留站长用户用于兼容性,其他用户从数据库读取
2025-08-15 22:34:26 +08:00
const ownerUser = process.env.USERNAME;
2026-01-24 18:17:19 +08:00
adminConfig.UserConfig.Users = [{
2025-08-15 22:34:26 +08:00
username: ownerUser!,
role: 'owner',
banned: false,
2026-01-24 18:17:19 +08:00
}];
2025-08-15 22:34:26 +08:00
// 采集源去重
const seenSourceKeys = new Set<string>();
adminConfig.SourceConfig = adminConfig.SourceConfig.filter((source) => {
if (seenSourceKeys.has(source.key)) {
return false;
}
seenSourceKeys.add(source.key);
return true;
});
// 自定义分类去重
const seenCustomCategoryKeys = new Set<string>();
adminConfig.CustomCategories = adminConfig.CustomCategories.filter((category) => {
if (seenCustomCategoryKeys.has(category.query + category.type)) {
return false;
}
seenCustomCategoryKeys.add(category.query + category.type);
return true;
});
2025-08-24 00:26:48 +08:00
// 直播源去重
const seenLiveKeys = new Set<string>();
adminConfig.LiveConfig = adminConfig.LiveConfig.filter((live) => {
if (seenLiveKeys.has(live.key)) {
return false;
}
seenLiveKeys.add(live.key);
return true;
});
2026-01-08 00:14:07 +08:00
// Emby配置迁移将旧格式迁移到新格式
if (adminConfig.EmbyConfig) {
// 如果是旧格式有ServerURL但没有Sources
if (adminConfig.EmbyConfig.ServerURL && !adminConfig.EmbyConfig.Sources) {
console.log('[Config] 检测到旧格式Emby配置自动迁移到新格式');
const oldConfig = adminConfig.EmbyConfig;
adminConfig.EmbyConfig = {
Sources: [{
key: 'default',
name: 'Emby',
enabled: oldConfig.Enabled ?? false,
2026-01-08 01:36:16 +08:00
ServerURL: oldConfig.ServerURL || '',
2026-01-08 00:14:07 +08:00
ApiKey: oldConfig.ApiKey,
Username: oldConfig.Username,
Password: oldConfig.Password,
UserId: oldConfig.UserId,
AuthToken: oldConfig.AuthToken,
Libraries: oldConfig.Libraries,
LastSyncTime: oldConfig.LastSyncTime,
ItemCount: oldConfig.ItemCount,
isDefault: true,
}],
};
}
// Emby源去重
2026-01-08 01:36:16 +08:00
if (adminConfig.EmbyConfig?.Sources) {
2026-01-08 00:14:07 +08:00
const seenEmbyKeys = new Set<string>();
adminConfig.EmbyConfig.Sources = adminConfig.EmbyConfig.Sources.filter((source) => {
if (seenEmbyKeys.has(source.key)) {
return false;
}
seenEmbyKeys.add(source.key);
return true;
});
}
}
2026-02-02 20:53:28 +08:00
// 确保音乐配置存在
if (!adminConfig.MusicConfig) {
adminConfig.MusicConfig = {
TuneHubEnabled: false,
TuneHubBaseUrl: 'https://tunehub.sayqz.com/api',
TuneHubApiKey: '',
OpenListCacheEnabled: false,
OpenListCacheURL: '',
OpenListCacheUsername: '',
OpenListCachePassword: '',
OpenListCachePath: '/music-cache',
2026-02-03 20:37:01 +08:00
OpenListCacheProxyEnabled: true,
2026-02-02 20:53:28 +08:00
};
}
2025-08-15 22:34:26 +08:00
return adminConfig;
}
2025-08-12 21:50:58 +08:00
export async function resetConfig() {
let originConfig: AdminConfig | null = null;
try {
originConfig = await db.getAdminConfig();
} catch (e) {
console.error('获取管理员配置失败:', e);
}
if (!originConfig) {
2025-08-13 13:20:58 +08:00
originConfig = {} as AdminConfig;
2025-08-13 22:07:28 +08:00
}
const adminConfig = await getInitConfig(originConfig.ConfigFile, originConfig.ConfigSubscribtion);
cachedConfig = adminConfig;
await db.saveAdminConfig(adminConfig);
2025-08-12 21:50:58 +08:00
return;
2025-08-12 21:50:58 +08:00
}
export async function getCacheTime(): Promise<number> {
const config = await getConfig();
return config.SiteConfig.SiteInterfaceCacheTime || 7200;
}
2025-08-20 19:37:36 +08:00
export async function getAvailableApiSites(user?: string): Promise<ApiSite[]> {
2025-08-12 21:50:58 +08:00
const config = await getConfig();
2025-08-20 19:37:36 +08:00
const allApiSites = config.SourceConfig.filter((s) => !s.disabled);
2025-08-21 13:05:46 +08:00
if (!user) {
2025-08-20 19:37:36 +08:00
return allApiSites;
}
2025-08-21 13:05:46 +08:00
2026-01-18 11:57:05 +08:00
// localStorage 模式下直接返回所有可用源
const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage';
if (storageType === 'localstorage') {
return allApiSites;
}
2025-12-24 00:24:50 +08:00
// 从V2存储中获取用户信息
const userInfoV2 = await db.getUserInfoV2(user);
if (!userInfoV2) {
2025-08-21 13:05:46 +08:00
return allApiSites;
}
// 优先根据用户自己的 enabledApis 配置查找
2025-12-24 00:24:50 +08:00
if (userInfoV2.enabledApis && userInfoV2.enabledApis.length > 0) {
const userApiSitesSet = new Set(userInfoV2.enabledApis);
2025-08-21 13:05:46 +08:00
return allApiSites.filter((s) => userApiSitesSet.has(s.key)).map((s) => ({
key: s.key,
name: s.name,
api: s.api,
detail: s.detail,
2025-12-28 21:01:49 +08:00
proxyMode: s.proxyMode,
2025-08-21 13:05:46 +08:00
}));
}
// 如果没有 enabledApis 配置,则根据 tags 查找
2025-12-24 00:24:50 +08:00
if (userInfoV2.tags && userInfoV2.tags.length > 0 && config.UserConfig.Tags) {
2025-08-21 13:05:46 +08:00
const enabledApisFromTags = new Set<string>();
// 遍历用户的所有 tags收集对应的 enabledApis
2025-12-24 00:24:50 +08:00
userInfoV2.tags.forEach(tagName => {
2025-08-21 13:05:46 +08:00
const tagConfig = config.UserConfig.Tags?.find(t => t.name === tagName);
if (tagConfig && tagConfig.enabledApis) {
tagConfig.enabledApis.forEach(apiKey => enabledApisFromTags.add(apiKey));
}
});
if (enabledApisFromTags.size > 0) {
return allApiSites.filter((s) => enabledApisFromTags.has(s.key)).map((s) => ({
key: s.key,
name: s.name,
api: s.api,
detail: s.detail,
2025-12-28 21:01:49 +08:00
proxyMode: s.proxyMode,
2025-08-21 13:05:46 +08:00
}));
}
}
// 如果都没有配置,返回所有可用的 API 站点
return allApiSites;
2025-08-12 21:50:58 +08:00
}
export async function setCachedConfig(config: AdminConfig) {
cachedConfig = config;
2026-01-14 20:02:45 +08:00
}
export async function clearConfigCache() {
cachedConfig = null as any;
configInitPromise = null;
2026-01-23 14:28:35 +08:00
}