(function() { 'use strict'; class UserDataSync { constructor() { this.username = null; this.data = { favorite_channels: [], download_concurrency: 16, batch_download_concurrency: 3, fab_position: { bottom: 30, right: 30 }, playback_history: [], program_reminders: [] }; this.isInitialized = false; this.pendingUpdates = {}; this.saveTimer = null; } /** * 初始化用户数据 */ init(username) { if (!username) { console.warn('⚠️ UserDataSync: 未提供用户名'); return false; } this.username = username; // ✅ 从 sessionStorage 加载(登录时后端已写入) const userDataKey = `user_data_${username}`; const savedData = sessionStorage.getItem(userDataKey); if (savedData) { try { const parsed = JSON.parse(savedData); this.data = { ...this.data, ...parsed }; console.log('✅ 用户数据已加载:', Object.keys(this.data)); } catch (e) { console.error('❌ 解析用户数据失败:', e); } } this.isInitialized = true; return true; } /** * 标记数据已修改(防抖保存) */ markChanged(key) { if (!this.isInitialized) return; this.pendingUpdates[key] = this.data[key]; // 防抖:1秒后保存 if (this.saveTimer) { clearTimeout(this.saveTimer); } this.saveTimer = setTimeout(() => { this.save(); }, 1000); } /** * 立即保存到后端 */ async save(force = false) { if (!this.isInitialized || !this.username) return false; if (!force && Object.keys(this.pendingUpdates).length === 0) return true; const updates = force ? this.data : this.pendingUpdates; try { // ✅ 保存到 sessionStorage(同步) const userDataKey = `user_data_${this.username}`; sessionStorage.setItem(userDataKey, JSON.stringify(this.data)); // ✅ 通过后端保存到 Redis const response = await fetch('/api/user/data/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: this.username, data: updates }) }); if (response.ok) { console.log('✅ 用户数据已同步到 Redis:', Object.keys(updates)); this.pendingUpdates = {}; return true; } else { console.warn('⚠️ 同步失败,数据已保存到本地'); return false; } } catch (error) { console.error('❌ 同步失败:', error); return false; } } // ==================== 便捷方法 ==================== getFavorites() { return this.data.favorite_channels || []; } setFavorites(favorites) { this.data.favorite_channels = Array.isArray(favorites) ? favorites : []; this.markChanged('favorite_channels'); } getDownloadConcurrency() { return this.data.download_concurrency || 16; } setDownloadConcurrency(concurrency) { const value = parseInt(concurrency); if (value >= 1 && value <= 32) { this.data.download_concurrency = value; this.markChanged('download_concurrency'); } } getBatchConcurrency() { return this.data.batch_download_concurrency || 3; } setBatchConcurrency(concurrency) { const value = parseInt(concurrency); if (value >= 1 && value <= 10) { this.data.batch_download_concurrency = value; this.markChanged('batch_download_concurrency'); } } getFabPosition() { return this.data.fab_position || { bottom: 30, right: 30 }; } setFabPosition(position) { if (position && typeof position === 'object') { this.data.fab_position = position; this.markChanged('fab_position'); } } getPlaybackHistory() { return this.data.playback_history || []; } addPlaybackHistory(item) { if (!Array.isArray(this.data.playback_history)) { this.data.playback_history = []; } // 去重 this.data.playback_history = this.data.playback_history.filter( h => h.path !== item.path ); // 添加到开头 this.data.playback_history.unshift(item); // 最多保留 50 条 if (this.data.playback_history.length > 50) { this.data.playback_history = this.data.playback_history.slice(0, 50); } this.markChanged('playback_history'); } getProgramReminders() { return this.data.program_reminders || []; } addProgramReminder(reminder) { if (!Array.isArray(this.data.program_reminders)) { this.data.program_reminders = []; } const exists = this.data.program_reminders.some( r => r.title === reminder.title && r.startTime === reminder.startTime ); if (!exists) { this.data.program_reminders.push(reminder); this.markChanged('program_reminders'); } } removeProgramReminder(reminderId) { if (Array.isArray(this.data.program_reminders)) { this.data.program_reminders = this.data.program_reminders.filter( r => r.id !== reminderId ); this.markChanged('program_reminders'); } } } // 创建全局单例 window.userDataSync = new UserDataSync(); // 页面卸载时保存 window.addEventListener('beforeunload', () => { if (window.userDataSync && window.userDataSync.isInitialized) { window.userDataSync.save(true); } }); console.log('✅ UserDataSync 已加载(无需 API)'); })();