UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

491 lines 18.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.themeManager = exports.ThemeManager = void 0; const events_1 = require("events"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const config_validator_1 = require("./config-validator"); const errors_1 = require("../utils/errors"); class ThemeManager extends events_1.EventEmitter { constructor(options = {}) { super(); this.themes = new Map(); this.currentThemeId = 'default'; this.customThemes = new Map(); this.previewMode = false; this.options = { themesDir: options.themesDir || path.join(os.homedir(), '.polyv-cli', 'themes'), autoSave: options.autoSave ?? true, enablePreview: options.enablePreview ?? true, }; this.themesDir = this.options.themesDir; this.ensureThemesDirectory(); this.loadBuiltInThemes(); this.loadCustomThemes(); } getAvailableThemes() { return Array.from(this.themes.keys()); } getTheme(themeId) { return this.themes.get(themeId); } getCurrentTheme() { const theme = this.themes.get(this.currentThemeId); if (!theme) { throw new errors_1.ConfigurationError(`Current theme '${this.currentThemeId}' not found`); } return theme; } getCurrentThemeId() { return this.currentThemeId; } async applyTheme(themeId) { const theme = this.themes.get(themeId); if (!theme) { throw new errors_1.ConfigurationError(`Theme '${themeId}' not found`); } const validation = config_validator_1.ConfigValidator.validateThemeConfig(theme); if (!validation.valid) { throw new errors_1.ConfigurationError(`Cannot apply invalid theme: ${config_validator_1.ConfigValidator.createErrorMessage(validation)}`); } const previousThemeId = this.currentThemeId; this.currentThemeId = themeId; try { await this.applyThemeToInterface(theme); this.emit('theme:applied', theme, previousThemeId); } catch (error) { this.currentThemeId = previousThemeId; throw new errors_1.ConfigurationError(`Failed to apply theme '${themeId}': ${error instanceof Error ? error.message : String(error)}`); } } async createCustomTheme(theme) { const validation = config_validator_1.ConfigValidator.validateThemeConfig(theme); if (!validation.valid) { throw new errors_1.ConfigurationError(`Cannot create invalid theme: ${config_validator_1.ConfigValidator.createErrorMessage(validation)}`); } if (this.themes.has(theme.id)) { throw new errors_1.ConfigurationError(`Theme with ID '${theme.id}' already exists`); } const customTheme = { ...theme, isBuiltIn: false, }; await this.saveCustomTheme(customTheme); this.themes.set(customTheme.id, customTheme); this.customThemes.set(customTheme.id, customTheme); this.emit('theme:created', customTheme); } async updateCustomTheme(themeId, updates) { const existingTheme = this.customThemes.get(themeId); if (!existingTheme) { throw new errors_1.ConfigurationError(`Custom theme '${themeId}' not found`); } if (existingTheme.isBuiltIn) { throw new errors_1.ConfigurationError(`Cannot update built-in theme '${themeId}'`); } const updatedTheme = { ...existingTheme, ...updates, id: themeId, isBuiltIn: false, }; const validation = config_validator_1.ConfigValidator.validateThemeConfig(updatedTheme); if (!validation.valid) { throw new errors_1.ConfigurationError(`Cannot update to invalid theme: ${config_validator_1.ConfigValidator.createErrorMessage(validation)}`); } await this.saveCustomTheme(updatedTheme); this.themes.set(themeId, updatedTheme); this.customThemes.set(themeId, updatedTheme); if (this.currentThemeId === themeId) { await this.applyThemeToInterface(updatedTheme); } this.emit('theme:updated', updatedTheme, existingTheme); } async deleteCustomTheme(themeId) { const theme = this.customThemes.get(themeId); if (!theme) { throw new errors_1.ConfigurationError(`Custom theme '${themeId}' not found`); } if (theme.isBuiltIn) { throw new errors_1.ConfigurationError(`Cannot delete built-in theme '${themeId}'`); } if (this.currentThemeId === themeId) { await this.applyTheme('default'); } const themeFile = path.join(this.themesDir, `${themeId}.json`); if (fs.existsSync(themeFile)) { await fs.promises.unlink(themeFile); } this.themes.delete(themeId); this.customThemes.delete(themeId); this.emit('theme:deleted', theme); } async exportTheme(themeId, filePath) { const theme = this.themes.get(themeId); if (!theme) { throw new errors_1.ConfigurationError(`Theme '${themeId}' not found`); } try { const themeJson = JSON.stringify(theme, null, 2); await fs.promises.writeFile(filePath, themeJson, 'utf8'); this.emit('theme:exported', theme, filePath); } catch (error) { throw new errors_1.ConfigurationError(`Failed to export theme to '${filePath}': ${error instanceof Error ? error.message : String(error)}`); } } async importTheme(filePath) { try { const fileContent = await fs.promises.readFile(filePath, 'utf8'); const theme = JSON.parse(fileContent); const validation = config_validator_1.ConfigValidator.validateThemeConfig(theme); if (!validation.valid) { throw new errors_1.ConfigurationError(`Invalid theme file: ${config_validator_1.ConfigValidator.createErrorMessage(validation)}`); } if (this.themes.has(theme.id)) { const originalId = theme.id; let counter = 1; while (this.themes.has(`${originalId}-${counter}`)) { counter++; } theme.id = `${originalId}-${counter}`; } theme.isBuiltIn = false; await this.createCustomTheme(theme); this.emit('theme:imported', theme, filePath); return theme; } catch (error) { if (error instanceof errors_1.ConfigurationError) { throw error; } throw new errors_1.ConfigurationError(`Failed to import theme from '${filePath}': ${error instanceof Error ? error.message : String(error)}`); } } async startPreview(themeId) { if (!this.options.enablePreview) { throw new errors_1.ConfigurationError('Theme preview is disabled'); } const theme = this.themes.get(themeId); if (!theme) { throw new errors_1.ConfigurationError(`Theme '${themeId}' not found`); } if (!this.previewMode) { this.originalThemeId = this.currentThemeId; } this.previewMode = true; await this.applyThemeToInterface(theme); this.emit('theme:preview-started', theme); } async endPreview() { if (!this.previewMode) { return; } this.previewMode = false; if (this.originalThemeId) { const originalTheme = this.themes.get(this.originalThemeId); if (originalTheme) { await this.applyThemeToInterface(originalTheme); } this.originalThemeId = undefined; } this.emit('theme:preview-ended'); } getCustomThemes() { return Array.from(this.customThemes.values()); } getBuiltInThemes() { return Array.from(this.themes.values()).filter(theme => theme.isBuiltIn); } isInPreviewMode() { return this.previewMode; } ensureThemesDirectory() { try { if (!fs.existsSync(this.themesDir)) { fs.mkdirSync(this.themesDir, { recursive: true }); } } catch (error) { throw new errors_1.ConfigurationError(`Failed to create themes directory: ${error}`); } } loadBuiltInThemes() { const defaultTheme = this.createDefaultTheme(); this.themes.set(defaultTheme.id, defaultTheme); const darkTheme = this.createDarkTheme(); this.themes.set(darkTheme.id, darkTheme); const lightTheme = this.createLightTheme(); this.themes.set(lightTheme.id, lightTheme); const highContrastTheme = this.createHighContrastTheme(); this.themes.set(highContrastTheme.id, highContrastTheme); } async loadCustomThemes() { try { if (!fs.existsSync(this.themesDir)) { return; } const files = await fs.promises.readdir(this.themesDir); const themeFiles = files.filter(file => file.endsWith('.json')); for (const file of themeFiles) { try { const filePath = path.join(this.themesDir, file); const fileContent = await fs.promises.readFile(filePath, 'utf8'); const theme = JSON.parse(fileContent); const validation = config_validator_1.ConfigValidator.validateThemeConfig(theme); if (validation.valid) { this.themes.set(theme.id, theme); this.customThemes.set(theme.id, theme); } else { console.warn(`Invalid theme file ${file}: ${validation.errors.join(', ')}`); } } catch (error) { console.warn(`Failed to load theme file ${file}: ${error}`); } } } catch (error) { console.warn(`Failed to load custom themes: ${error}`); } } async saveCustomTheme(theme) { const themeFile = path.join(this.themesDir, `${theme.id}.json`); const themeJson = JSON.stringify(theme, null, 2); try { await fs.promises.writeFile(themeFile, themeJson, 'utf8'); } catch (error) { throw new errors_1.ConfigurationError(`Failed to save theme '${theme.id}': ${error instanceof Error ? error.message : String(error)}`); } } async applyThemeToInterface(theme) { this.emit('theme:interface-update', theme); const delay = process.env['NODE_ENV'] === 'test' ? 1 : 100; await new Promise(resolve => setTimeout(resolve, delay)); } createDefaultTheme() { return { id: 'default', name: 'Default', description: 'Default monitoring interface theme', isBuiltIn: true, colors: { primary: '#0066cc', secondary: '#6c757d', background: '#000000', foreground: '#ffffff', accent: '#17a2b8', error: '#dc3545', warning: '#ffc107', success: '#28a745', info: '#17a2b8', muted: '#6c757d', highlight: '#ffff00', border: '#666666', selection: '#0066cc', }, fonts: { family: 'monospace', size: 12, weight: 'normal', style: 'normal', }, borders: { type: 'line', style: 'solid', color: '#666666', }, components: this.createDefaultComponentStyles(), }; } createDarkTheme() { return { id: 'dark', name: 'Dark', description: 'Dark theme optimized for low-light environments', isBuiltIn: true, colors: { primary: '#0d6efd', secondary: '#6c757d', background: '#121212', foreground: '#e0e0e0', accent: '#bb86fc', error: '#cf6679', warning: '#f9c74f', success: '#4caf50', info: '#2196f3', muted: '#757575', highlight: '#ffeb3b', border: '#333333', selection: '#bb86fc', }, fonts: { family: 'monospace', size: 12, weight: 'normal', style: 'normal', }, borders: { type: 'line', style: 'solid', color: '#333333', }, components: this.createDarkComponentStyles(), }; } createLightTheme() { return { id: 'light', name: 'Light', description: 'Light theme for bright environments', isBuiltIn: true, colors: { primary: '#0066cc', secondary: '#6c757d', background: '#ffffff', foreground: '#000000', accent: '#6f42c1', error: '#dc3545', warning: '#fd7e14', success: '#198754', info: '#0dcaf0', muted: '#6c757d', highlight: '#fff3cd', border: '#dee2e6', selection: '#0066cc', }, fonts: { family: 'monospace', size: 12, weight: 'normal', style: 'normal', }, borders: { type: 'line', style: 'solid', color: '#dee2e6', }, components: this.createLightComponentStyles(), }; } createHighContrastTheme() { return { id: 'high-contrast', name: 'High Contrast', description: 'High contrast theme for accessibility', isBuiltIn: true, colors: { primary: '#ffff00', secondary: '#ffffff', background: '#000000', foreground: '#ffffff', accent: '#00ffff', error: '#ff0000', warning: '#ffff00', success: '#00ff00', info: '#00ffff', muted: '#808080', highlight: '#ffff00', border: '#ffffff', selection: '#ffff00', }, fonts: { family: 'monospace', size: 14, weight: 'bold', style: 'normal', }, borders: { type: 'line', style: 'solid', color: '#ffffff', }, components: this.createHighContrastComponentStyles(), }; } createDefaultComponentStyles() { return { header: { fg: '#ffffff', bg: '#0066cc', bold: true }, content: { fg: '#ffffff', bg: '#000000' }, status: { fg: '#17a2b8', bg: '#000000' }, border: { fg: '#666666' }, scrollbar: { fg: '#666666', bg: '#333333' }, selection: { fg: '#ffffff', bg: '#0066cc' }, }; } createDarkComponentStyles() { return { header: { fg: '#e0e0e0', bg: '#333333', bold: true }, content: { fg: '#e0e0e0', bg: '#121212' }, status: { fg: '#bb86fc', bg: '#121212' }, border: { fg: '#333333' }, scrollbar: { fg: '#555555', bg: '#222222' }, selection: { fg: '#000000', bg: '#bb86fc' }, }; } createLightComponentStyles() { return { header: { fg: '#000000', bg: '#f8f9fa', bold: true }, content: { fg: '#000000', bg: '#ffffff' }, status: { fg: '#6f42c1', bg: '#ffffff' }, border: { fg: '#dee2e6' }, scrollbar: { fg: '#adb5bd', bg: '#f8f9fa' }, selection: { fg: '#ffffff', bg: '#0066cc' }, }; } createHighContrastComponentStyles() { return { header: { fg: '#000000', bg: '#ffff00', bold: true }, content: { fg: '#ffffff', bg: '#000000' }, status: { fg: '#00ffff', bg: '#000000', bold: true }, border: { fg: '#ffffff' }, scrollbar: { fg: '#ffffff', bg: '#000000' }, selection: { fg: '#000000', bg: '#ffff00' }, }; } destroy() { this.removeAllListeners(); this.themes.clear(); this.customThemes.clear(); } } exports.ThemeManager = ThemeManager; exports.themeManager = new ThemeManager(); //# sourceMappingURL=theme-manager.js.map