193 lines
5.1 KiB
TypeScript
193 lines
5.1 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||
|
||
import { AdminConfig } from './admin.types';
|
||
import { getConfig } from './config';
|
||
import { EmbyClient } from './emby.client';
|
||
|
||
interface EmbySourceConfig {
|
||
key: string;
|
||
name: string;
|
||
enabled: boolean;
|
||
ServerURL: string;
|
||
ApiKey?: string;
|
||
Username?: string;
|
||
Password?: string;
|
||
UserId?: string;
|
||
AuthToken?: string;
|
||
Libraries?: string[];
|
||
LastSyncTime?: number;
|
||
ItemCount?: number;
|
||
isDefault?: boolean;
|
||
// 高级流媒体选项
|
||
removeEmbyPrefix?: boolean;
|
||
appendMediaSourceId?: boolean;
|
||
transcodeMp4?: boolean;
|
||
proxyPlay?: boolean; // 视频播放代理开关
|
||
}
|
||
|
||
class EmbyManager {
|
||
private static instance: EmbyManager;
|
||
private clients: Map<string, EmbyClient> = new Map();
|
||
|
||
private constructor() {}
|
||
|
||
static getInstance(): EmbyManager {
|
||
if (!EmbyManager.instance) {
|
||
EmbyManager.instance = new EmbyManager();
|
||
}
|
||
return EmbyManager.instance;
|
||
}
|
||
|
||
/**
|
||
* 从配置中获取所有Emby源(支持新旧格式)
|
||
*/
|
||
private async getSources(): Promise<EmbySourceConfig[]> {
|
||
const config = await getConfig();
|
||
|
||
// 如果是新格式(Sources数组)
|
||
if (config.EmbyConfig?.Sources && Array.isArray(config.EmbyConfig.Sources)) {
|
||
return config.EmbyConfig.Sources;
|
||
}
|
||
|
||
// 如果是旧格式(单源配置),转换为数组格式
|
||
if (config.EmbyConfig?.ServerURL) {
|
||
return [{
|
||
key: 'default',
|
||
name: 'Emby',
|
||
enabled: config.EmbyConfig.Enabled ?? false,
|
||
ServerURL: config.EmbyConfig.ServerURL,
|
||
ApiKey: config.EmbyConfig.ApiKey,
|
||
Username: config.EmbyConfig.Username,
|
||
Password: config.EmbyConfig.Password,
|
||
UserId: config.EmbyConfig.UserId,
|
||
AuthToken: config.EmbyConfig.AuthToken,
|
||
Libraries: config.EmbyConfig.Libraries,
|
||
LastSyncTime: config.EmbyConfig.LastSyncTime,
|
||
ItemCount: config.EmbyConfig.ItemCount,
|
||
isDefault: true,
|
||
}];
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
/**
|
||
* 获取指定key的EmbyClient
|
||
* @param key Emby源的key,如果不指定则使用默认源
|
||
*/
|
||
async getClient(key?: string): Promise<EmbyClient> {
|
||
const sources = await this.getSources();
|
||
|
||
if (sources.length === 0) {
|
||
throw new Error('未配置 Emby 源');
|
||
}
|
||
|
||
// 如果没有指定key,使用默认源(第一个或标记为default的)
|
||
if (!key) {
|
||
const defaultSource = sources.find(s => s.isDefault) || sources[0];
|
||
key = defaultSource.key;
|
||
}
|
||
|
||
// 从缓存获取或创建新实例
|
||
if (!this.clients.has(key)) {
|
||
const sourceConfig = sources.find(s => s.key === key);
|
||
if (!sourceConfig) {
|
||
throw new Error(`未找到 Emby 源: ${key}`);
|
||
}
|
||
|
||
if (!sourceConfig.enabled) {
|
||
throw new Error(`Emby 源已禁用: ${sourceConfig.name}`);
|
||
}
|
||
|
||
this.clients.set(key, new EmbyClient(sourceConfig));
|
||
}
|
||
|
||
return this.clients.get(key)!;
|
||
}
|
||
|
||
/**
|
||
* 获取所有启用的EmbyClient
|
||
*/
|
||
async getAllClients(): Promise<Map<string, { client: EmbyClient; config: EmbySourceConfig }>> {
|
||
const sources = await this.getSources();
|
||
const enabledSources = sources.filter(s => s.enabled);
|
||
const result = new Map<string, { client: EmbyClient; config: EmbySourceConfig }>();
|
||
|
||
for (const source of enabledSources) {
|
||
if (!this.clients.has(source.key)) {
|
||
this.clients.set(source.key, new EmbyClient(source));
|
||
}
|
||
result.set(source.key, {
|
||
client: this.clients.get(source.key)!,
|
||
config: source,
|
||
});
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 获取所有启用的Emby源配置
|
||
*/
|
||
async getEnabledSources(): Promise<EmbySourceConfig[]> {
|
||
const sources = await this.getSources();
|
||
return sources.filter(s => s.enabled);
|
||
}
|
||
|
||
/**
|
||
* 检查是否配置了Emby
|
||
*/
|
||
async hasEmby(): Promise<boolean> {
|
||
const sources = await this.getSources();
|
||
return sources.some(s => s.enabled && s.ServerURL);
|
||
}
|
||
|
||
/**
|
||
* 清除缓存的客户端实例
|
||
*/
|
||
clearCache() {
|
||
this.clients.clear();
|
||
}
|
||
}
|
||
|
||
export const embyManager = EmbyManager.getInstance();
|
||
|
||
/**
|
||
* 配置迁移函数:将旧格式配置迁移到新格式
|
||
*/
|
||
export function migrateEmbyConfig(config: AdminConfig): AdminConfig {
|
||
// 如果已经是新格式,直接返回
|
||
if (config.EmbyConfig?.Sources) {
|
||
return config;
|
||
}
|
||
|
||
// 如果是旧格式,迁移到新格式
|
||
if (config.EmbyConfig && config.EmbyConfig.ServerURL) {
|
||
const oldConfig = config.EmbyConfig;
|
||
config.EmbyConfig = {
|
||
Sources: [{
|
||
key: 'default',
|
||
name: 'Emby',
|
||
enabled: oldConfig.Enabled ?? false,
|
||
ServerURL: oldConfig.ServerURL || '',
|
||
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,
|
||
// 高级选项默认值
|
||
removeEmbyPrefix: false,
|
||
appendMediaSourceId: false,
|
||
transcodeMp4: false,
|
||
proxyPlay: false,
|
||
}],
|
||
};
|
||
}
|
||
|
||
return config;
|
||
}
|