| (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;
|
|
|
|
|
| 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];
|
|
|
|
|
| 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 {
|
|
|
| const userDataKey = `user_data_${this.username}`;
|
| sessionStorage.setItem(userDataKey, JSON.stringify(this.data));
|
|
|
|
|
| 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);
|
|
|
|
|
| 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)');
|
|
|
| })(); |