export interface ProcessDisplayNamePreset { match: string displayName: string } const DEFAULT_IGNORED_WINDOW_KEYWORDS = [ 'NVIDIA Overlay', 'Twinkle Tray Panel' ] const DEFAULT_PROCESS_DISPLAY_NAME_PRESETS: ProcessDisplayNamePreset[] = [ { match: 'microsoft vs code\\code.exe', displayName: 'Visual Studio Code' }, { match: 'msedge.exe', displayName: 'Microsoft Edge' }, { match: 'windowsTerminal.exe', displayName: '终端' }, { match: 'windowsterminal.exe', displayName: '终端' }, { match: 'blender.exe', displayName: 'Blender' }, { match: 'chrome.exe', displayName: 'Google Chrome' }, { match: 'steamwebhelper.exe', displayName: 'Steam' }, { match: 'steam.exe', displayName: 'Steam' }, { match: 'bandizip.exe', displayName: 'Bandizip' }, { match: 'explorer.exe', displayName: '文件资源管理器' }, { match: 'devenv.exe', displayName: 'Visual Studio' }, { match: 'idea64.exe', displayName: 'IntelliJ IDEA' }, { match: 'pycharm64.exe', displayName: 'PyCharm' }, { match: 'cursor.exe', displayName: 'Cursor' }, { match: 'obsidian.exe', displayName: 'Obsidian' }, { match: 'notion.exe', displayName: 'Notion' }, { match: 'wechat.exe', displayName: '微信' }, { match: 'qq.exe', displayName: 'QQ' }, { match: 'teams.exe', displayName: 'Microsoft Teams' }, { match: 'telegram.exe', displayName: 'Telegram' } ] const parseCommaSeparatedEnv = (value: string | undefined, fallback: string[]) => { if (!value?.trim()) { return fallback } const parsed = value .split(',') .map(item => item.trim()) .filter(Boolean) return parsed.length > 0 ? parsed : fallback } const parseProcessDisplayNamePresetsEnv = ( value: string | undefined, fallback: ProcessDisplayNamePreset[] ) => { if (!value?.trim()) { return fallback } const parsed = value .split(';') .map(item => item.trim()) .filter(Boolean) .map((item) => { const separatorIndex = item.indexOf('=') if (separatorIndex <= 0 || separatorIndex === item.length - 1) { return null } const match = item.slice(0, separatorIndex).trim() const displayName = item.slice(separatorIndex + 1).trim() if (!match || !displayName) { return null } return { match, displayName } }) .filter((item): item is ProcessDisplayNamePreset => item !== null) return parsed.length > 0 ? parsed : fallback } export const IGNORED_WINDOW_KEYWORDS = parseCommaSeparatedEnv( process.env.IGNORED_WINDOW_KEYWORDS, DEFAULT_IGNORED_WINDOW_KEYWORDS ) export const PROCESS_DISPLAY_NAME_PRESETS = parseProcessDisplayNamePresetsEnv( process.env.PROCESS_DISPLAY_NAME_PRESETS, DEFAULT_PROCESS_DISPLAY_NAME_PRESETS ) export const config = { port: process.env.PORT || 3000, auth: { username: process.env.AUTH_USERNAME || 'admin', password: process.env.AUTH_PASSWORD || 'password', secret: process.env.AUTH_SECRET || 'winupdate-neo-secret-key' }, windows: { ignoredKeywords: IGNORED_WINDOW_KEYWORDS }, screenTime: { processDisplayNamePresets: PROCESS_DISPLAY_NAME_PRESETS }, // For file upload settings upload: { maxFileSize: 10 * 1024 * 1024, // 10MB allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'application/x-msdownload'] } }