feat: implement iptv

This commit is contained in:
shinya
2025-08-24 00:26:48 +08:00
parent eadd93fde6
commit 0a8c255279
22 changed files with 2399 additions and 12 deletions
+80
View File
@@ -11,6 +11,13 @@ export interface ApiSite {
detail?: string;
}
export interface LiveCfg {
name: string;
url: string;
ua?: string;
epg?: string; // 节目单
}
interface ConfigFileStruct {
cache_time?: number;
api_site?: {
@@ -21,6 +28,9 @@ interface ConfigFileStruct {
type: 'movie' | 'tv';
query: string;
}[];
lives?: {
[key: string]: LiveCfg;
}
}
export const API_CONFIG = {
@@ -46,6 +56,7 @@ export const API_CONFIG = {
// 在模块加载时根据环境决定配置来源
let cachedConfig: AdminConfig;
// 从配置文件补充管理员配置
export function refineConfig(adminConfig: AdminConfig): AdminConfig {
let fileConfig: ConfigFileStruct;
@@ -131,6 +142,43 @@ export function refineConfig(adminConfig: AdminConfig): AdminConfig {
// 将 Map 转换回数组
adminConfig.CustomCategories = Array.from(currentCustomCategories.values());
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());
return adminConfig;
}
@@ -176,6 +224,7 @@ async function getInitConfig(configFile: string, subConfig: {
},
SourceConfig: [],
CustomCategories: [],
LiveConfig: [],
};
// 补充用户信息
@@ -220,6 +269,23 @@ async function getInitConfig(configFile: string, subConfig: {
});
});
// 从配置文件中补充直播源信息
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,
});
});
return adminConfig;
}
@@ -261,6 +327,9 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
if (!adminConfig.CustomCategories || !Array.isArray(adminConfig.CustomCategories)) {
adminConfig.CustomCategories = [];
}
if (!adminConfig.LiveConfig || !Array.isArray(adminConfig.LiveConfig)) {
adminConfig.LiveConfig = [];
}
// 站长变更自检
const ownerUser = process.env.USERNAME;
@@ -311,6 +380,17 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
seenCustomCategoryKeys.add(category.query + category.type);
return true;
});
// 直播源去重
const seenLiveKeys = new Set<string>();
adminConfig.LiveConfig = adminConfig.LiveConfig.filter((live) => {
if (seenLiveKeys.has(live.key)) {
return false;
}
seenLiveKeys.add(live.key);
return true;
});
return adminConfig;
}