// UI相关函数 function toggleSettings(e) { // 强化的密码保护校验 - 防止绕过 try { if (window.ensurePasswordProtection) { window.ensurePasswordProtection(); } else { // 兼容性检查 if (window.isPasswordProtected && window.isPasswordVerified) { if (window.isPasswordProtected() && !window.isPasswordVerified()) { showPasswordModal && showPasswordModal(); return; } } } } catch (error) { console.warn('Password protection check failed:', error.message); return; } // 阻止事件冒泡,防止触发document的点击事件 e && e.stopPropagation(); const panel = document.getElementById('settingsPanel'); panel.classList.toggle('show'); } // 改进的Toast显示函数 - 支持队列显示多个Toast const toastQueue = []; let isShowingToast = false; function showToast(message, type = 'error') { // 首先确保toast元素存在 let toast = document.getElementById('toast'); let toastMessage = document.getElementById('toastMessage'); // 如果toast元素不存在,创建它 if (!toast) { toast = document.createElement('div'); toast.id = 'toast'; toast.className = 'fixed top-4 left-1/2 -translate-x-1/2 px-6 py-3 rounded-lg shadow-lg transform transition-all duration-300 z-50 opacity-0'; toast.style = 'z-index: 2147483647' toastMessage = document.createElement('p'); toastMessage.id = 'toastMessage'; toast.appendChild(toastMessage); document.body.appendChild(toast); } // 将新的toast添加到队列 toastQueue.push({ message, type }); // 如果当前没有显示中的toast,则开始显示 if (!isShowingToast) { showNextToast(); } } function showNextToast() { if (toastQueue.length === 0) { isShowingToast = false; return; } isShowingToast = true; const { message, type } = toastQueue.shift(); const toast = document.getElementById('toast'); const toastMessage = document.getElementById('toastMessage'); const bgColors = { 'error': 'bg-red-500', 'success': 'bg-green-500', 'info': 'bg-blue-500', 'warning': 'bg-yellow-500' }; const bgColor = bgColors[type] || bgColors.error; toast.className = `fixed top-4 left-1/2 -translate-x-1/2 px-6 py-3 rounded-lg shadow-lg transform transition-all duration-300 ${bgColor} text-white z-50`; toastMessage.textContent = message; // 显示提示 toast.style.opacity = '1'; toast.style.transform = 'translateX(-50%) translateY(0)'; // 3秒后自动隐藏 setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translateX(-50%) translateY(-100%)'; // 等待动画完成后显示下一个toast setTimeout(() => { showNextToast(); }, 300); }, 3000); } // 添加显示/隐藏 loading 的函数 let loadingTimeoutId = null; function showLoading(message = '加载中...') { // 清除任何现有的超时 if (loadingTimeoutId) { clearTimeout(loadingTimeoutId); } const loading = document.getElementById('loading'); const messageEl = loading.querySelector('p'); messageEl.textContent = message; loading.style.display = 'flex'; // 设置30秒后自动关闭loading,防止无限loading loadingTimeoutId = setTimeout(() => { hideLoading(); showToast('操作超时,请稍后重试', 'warning'); }, 30000); } function hideLoading() { // 清除超时 if (loadingTimeoutId) { clearTimeout(loadingTimeoutId); loadingTimeoutId = null; } const loading = document.getElementById('loading'); loading.style.display = 'none'; } function updateSiteStatus(isAvailable) { const statusEl = document.getElementById('siteStatus'); if (isAvailable) { statusEl.innerHTML = ' 可用'; } else { statusEl.innerHTML = ' 不可用'; } } function closeModal() { document.getElementById('modal').classList.add('hidden'); // 清除 iframe 内容 document.getElementById('modalContent').innerHTML = ''; } // 获取搜索历史的增强版本 - 支持新旧格式 function getSearchHistory() { try { const data = localStorage.getItem(SEARCH_HISTORY_KEY); if (!data) return []; const parsed = JSON.parse(data); // 检查是否是数组 if (!Array.isArray(parsed)) return []; // 支持旧格式(字符串数组)和新格式(对象数组) return parsed.map(item => { if (typeof item === 'string') { return { text: item, timestamp: 0 }; } return item; }).filter(item => item && item.text); } catch (e) { console.error('获取搜索历史出错:', e); return []; } } // 保存搜索历史的增强版本 - 添加时间戳和最大数量限制,现在缓存2个月 function saveSearchHistory(query) { if (!query || !query.trim()) return; // 清理输入,防止XSS query = query.trim().substring(0, 50).replace(//g, '>'); let history = getSearchHistory(); // 获取当前时间 const now = Date.now(); // 过滤掉超过2个月的记录(约60天,60*24*60*60*1000 = 5184000000毫秒) history = history.filter(item => typeof item === 'object' && item.timestamp && (now - item.timestamp < 5184000000) ); // 删除已存在的相同项 history = history.filter(item => typeof item === 'object' ? item.text !== query : item !== query ); // 新项添加到开头,包含时间戳 history.unshift({ text: query, timestamp: now }); // 限制历史记录数量 if (history.length > MAX_HISTORY_ITEMS) { history = history.slice(0, MAX_HISTORY_ITEMS); } try { localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(history)); } catch (e) { console.error('保存搜索历史失败:', e); // 如果存储失败(可能是localStorage已满),尝试清理旧数据 try { localStorage.removeItem(SEARCH_HISTORY_KEY); localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(history.slice(0, 3))); } catch (e2) { console.error('再次保存搜索历史失败:', e2); } } renderSearchHistory(); } // 渲染最近搜索历史的增强版本 function renderSearchHistory() { const historyContainer = document.getElementById('recentSearches'); if (!historyContainer) return; const history = getSearchHistory(); if (history.length === 0) { historyContainer.innerHTML = ''; return; } // 创建一个包含标题和清除按钮的行 historyContainer.innerHTML = `
最近搜索:
`; history.forEach(item => { const tag = document.createElement('button'); tag.className = 'search-tag flex items-center gap-1'; const textSpan = document.createElement('span'); textSpan.textContent = item.text; tag.appendChild(textSpan); // 添加删除按钮 const deleteButton = document.createElement('span'); deleteButton.className = 'pl-1 text-gray-500 hover:text-red-500 transition-colors'; deleteButton.innerHTML = ''; deleteButton.onclick = function(e) { // 阻止事件冒泡,避免触发搜索 e.stopPropagation(); // 删除对应历史记录 deleteSingleSearchHistory(item.text); // 重新渲染搜索历史 renderSearchHistory(); }; tag.appendChild(deleteButton); // 添加时间提示(如果有时间戳) if (item.timestamp) { const date = new Date(item.timestamp); tag.title = `搜索于: ${date.toLocaleString()}`; } tag.onclick = function() { document.getElementById('searchInput').value = item.text; search(); }; historyContainer.appendChild(tag); }); } // 删除单条搜索历史记录 function deleteSingleSearchHistory(query) { // 当url中包含删除的关键词时,页面刷新后会自动加入历史记录,导致误认为删除功能有bug。此问题无需修复,功能无实际影响。 try { let history = getSearchHistory(); // 过滤掉要删除的记录 history = history.filter(item => item.text !== query); console.log('更新后的搜索历史:', history); localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(history)); } catch (e) { console.error('删除单条搜索历史失败:', e); showToast('删除单条搜索历史失败', 'error'); } } // 增加清除搜索历史功能 function clearSearchHistory() { // 密码保护校验 if (window.isPasswordProtected && window.isPasswordVerified) { if (window.isPasswordProtected() && !window.isPasswordVerified()) { showPasswordModal && showPasswordModal(); return; } } try { localStorage.removeItem(SEARCH_HISTORY_KEY); renderSearchHistory(); showToast('搜索历史已清除', 'success'); } catch (e) { console.error('清除搜索历史失败:', e); showToast('清除搜索历史失败:', 'error'); } } // 历史面板相关函数 function toggleHistory(e) { // 密码保护校验 if (window.isPasswordProtected && window.isPasswordVerified) { if (window.isPasswordProtected() && !window.isPasswordVerified()) { showPasswordModal && showPasswordModal(); return; } } if (e) e.stopPropagation(); const panel = document.getElementById('historyPanel'); if (panel) { panel.classList.toggle('show'); // 如果打开了历史记录面板,则加载历史数据 if (panel.classList.contains('show')) { loadViewingHistory(); } // 如果设置面板是打开的,则关闭它 const settingsPanel = document.getElementById('settingsPanel'); if (settingsPanel && settingsPanel.classList.contains('show')) { settingsPanel.classList.remove('show'); } } } // 格式化时间戳为友好的日期时间格式 function formatTimestamp(timestamp) { const date = new Date(timestamp); const now = new Date(); const diff = now - date; // 小于1小时,显示"X分钟前" if (diff < 3600000) { const minutes = Math.floor(diff / 60000); return minutes <= 0 ? '刚刚' : `${minutes}分钟前`; } // 小于24小时,显示"X小时前" if (diff < 86400000) { const hours = Math.floor(diff / 3600000); return `${hours}小时前`; } // 小于7天,显示"X天前" if (diff < 604800000) { const days = Math.floor(diff / 86400000); return `${days}天前`; } // 其他情况,显示完整日期 const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); const hour = date.getHours().toString().padStart(2, '0'); const minute = date.getMinutes().toString().padStart(2, '0'); return `${year}-${month}-${day} ${hour}:${minute}`; } // 获取观看历史记录 function getViewingHistory() { try { const data = localStorage.getItem('viewingHistory'); return data ? JSON.parse(data) : []; } catch (e) { console.error('获取观看历史失败:', e); return []; } } // 加载观看历史并渲染 function loadViewingHistory() { const historyList = document.getElementById('historyList'); if (!historyList) return; const history = getViewingHistory(); if (history.length === 0) { historyList.innerHTML = `
暂无观看记录
`; return; } // 渲染历史记录 historyList.innerHTML = history.map(item => { // 防止XSS const safeTitle = item.title .replace(//g, '>') .replace(/"/g, '"'); const safeSource = item.sourceName ? item.sourceName.replace(//g, '>').replace(/"/g, '"') : '未知来源'; const episodeText = item.episodeIndex !== undefined ? `第${item.episodeIndex + 1}集` : ''; // 格式化剧集信息 let episodeInfoHtml = ''; if (item.episodes && Array.isArray(item.episodes) && item.episodes.length > 0) { const totalEpisodes = item.episodes.length; const syncStatus = item.lastSyncTime ? `` : ``; episodeInfoHtml = `共${totalEpisodes}集 ${syncStatus}`; } // 格式化进度信息 let progressHtml = ''; if (item.playbackPosition && item.duration && item.playbackPosition > 10 && item.playbackPosition < item.duration * 0.95) { const percent = Math.round((item.playbackPosition / item.duration) * 100); const formattedTime = formatPlaybackTime(item.playbackPosition); const formattedDuration = formatPlaybackTime(item.duration); progressHtml = `
${formattedTime} / ${formattedDuration}
`; } // 为防止XSS,使用encodeURIComponent编码URL const safeURL = encodeURIComponent(item.url); // 构建历史记录项HTML,添加删除按钮,需要放在position:relative的容器中 return `
${safeTitle}
${episodeText} ${episodeText ? '·' : ''} ${safeSource} ${episodeInfoHtml ? '·' : ''} ${episodeInfoHtml}
${progressHtml}
${formatTimestamp(item.timestamp)}
`; }).join(''); // 检查是否存在较多历史记录,添加底部边距确保底部按钮不会挡住内容 if (history.length > 5) { historyList.classList.add('pb-4'); } } // 格式化播放时间为 mm:ss 格式 function formatPlaybackTime(seconds) { if (!seconds || isNaN(seconds)) return '00:00'; const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.floor(seconds % 60); return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } // 删除单个历史记录项 function deleteHistoryItem(encodedUrl) { try { // 解码URL const url = decodeURIComponent(encodedUrl); // 获取当前历史记录 const history = getViewingHistory(); // 过滤掉要删除的项 const newHistory = history.filter(item => item.url !== url); // 保存回localStorage localStorage.setItem('viewingHistory', JSON.stringify(newHistory)); // 重新加载历史记录显示 loadViewingHistory(); // 显示成功提示 showToast('已删除该记录', 'success'); } catch (e) { console.error('删除历史记录项失败:', e); showToast('删除记录失败', 'error'); } } // 从历史记录播放 async function playFromHistory(url, title, episodeIndex, playbackPosition = 0) { // console.log('[playFromHistory in ui.js] Called with:', { url, title, episodeIndex, playbackPosition }); // Log 1 try { let episodesList = []; let historyItem = null; // To store the full history item let syncSuccessful = false; // 检查viewingHistory,查找匹配的项 const historyRaw = localStorage.getItem('viewingHistory'); if (historyRaw) { const history = JSON.parse(historyRaw); historyItem = history.find(item => item.url === url); // console.log('[playFromHistory in ui.js] Found historyItem:', historyItem ? JSON.parse(JSON.stringify(historyItem)) : null); // Log 2 (stringify/parse for deep copy) if (historyItem) { // console.log('[playFromHistory in ui.js] historyItem.vod_id:', historyItem.vod_id, 'historyItem.sourceName:', historyItem.sourceName); // Log 3 } if (historyItem && historyItem.episodes && Array.isArray(historyItem.episodes)) { episodesList = historyItem.episodes; // Default to stored episodes // console.log(`从历史记录找到视频 "${title}" 的集数数据 (默认):`, episodesList.length); } } // Always attempt to fetch fresh episode list if we have the necessary info if (historyItem && historyItem.vod_id && historyItem.sourceName) { // Show loading toast to indicate syncing showToast('正在同步最新剧集列表...', 'info'); // console.log(`[playFromHistory in ui.js] Attempting to fetch details for vod_id: ${historyItem.vod_id}, sourceName: ${historyItem.sourceName}`); // Log 4 try { // Construct the API URL for detail fetching // historyItem.sourceName is used as the sourceCode here // Add a cache buster timestamp const timestamp = new Date().getTime(); const apiUrl = `/api/detail?id=${encodeURIComponent(historyItem.vod_id)}&source=${encodeURIComponent(historyItem.sourceName)}&_t=${timestamp}`; // Add timeout to the fetch request const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout const response = await fetch(apiUrl, { signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } const videoDetails = await response.json(); if (videoDetails && videoDetails.episodes && videoDetails.episodes.length > 0) { const oldEpisodeCount = episodesList.length; episodesList = videoDetails.episodes; syncSuccessful = true; // Show success message with episode count info const newEpisodeCount = episodesList.length; if (newEpisodeCount > oldEpisodeCount) { showToast(`已同步最新剧集列表 (${newEpisodeCount}集,新增${newEpisodeCount - oldEpisodeCount}集)`, 'success'); } else if (newEpisodeCount === oldEpisodeCount) { showToast(`剧集列表已是最新 (${newEpisodeCount}集)`, 'success'); } else { showToast(`已同步最新剧集列表 (${newEpisodeCount}集)`, 'success'); } // console.log(`成功获取 "${title}" 最新剧集列表:`, episodesList.length, "集"); // Update the history item in localStorage with the fresh episodes if (historyItem) { historyItem.episodes = [...episodesList]; // Deep copy historyItem.lastSyncTime = Date.now(); // Add sync timestamp const history = JSON.parse(historyRaw); // Re-parse to ensure we have the latest version const idx = history.findIndex(item => item.url === url); if (idx !== -1) { history[idx] = { ...history[idx], ...historyItem }; // Merge, ensuring other properties are kept localStorage.setItem('viewingHistory', JSON.stringify(history)); // console.log("观看历史中的剧集列表已更新。"); } } } else { // console.log(`未能获取 "${title}" 的最新剧集列表,或列表为空。将使用已存储的剧集。`); showToast('未获取到最新剧集信息,使用缓存数据', 'warning'); } } catch (fetchError) { // console.error(`获取 "${title}" 最新剧集列表失败:`, fetchError, "将使用已存储的剧集。"); if (fetchError.name === 'AbortError') { showToast('同步剧集列表超时,使用缓存数据', 'warning'); } else { showToast('同步剧集列表失败,使用缓存数据', 'warning'); } } } else if (historyItem) { // console.log(`历史记录项 "${title}" 缺少 vod_id 或 sourceName,无法刷新剧集列表。将使用已存储的剧集。`); showToast('无法同步剧集列表,使用缓存数据', 'info'); } // 如果在历史记录中没找到,尝试使用上一个会话的集数数据 if (episodesList.length === 0) { try { const storedEpisodes = JSON.parse(localStorage.getItem('currentEpisodes') || '[]'); if (storedEpisodes.length > 0) { episodesList = storedEpisodes; // console.log(`使用localStorage中的集数数据:`, episodesList.length); } } catch (e) { // console.error('解析currentEpisodes失败:', e); } } // 将剧集列表保存到localStorage,播放器页面会读取它 if (episodesList.length > 0) { localStorage.setItem('currentEpisodes', JSON.stringify(episodesList)); // console.log(`已将剧集列表保存到localStorage,共 ${episodesList.length} 集`); } // 保存当前页面URL作为返回地址 let currentPath; if (window.location.pathname.startsWith('/player.html') || window.location.pathname.startsWith('/watch.html')) { currentPath = localStorage.getItem('lastPageUrl') || '/'; } else { currentPath = window.location.origin + window.location.pathname + window.location.search; } localStorage.setItem('lastPageUrl', currentPath); // 构造播放器URL let playerUrl; const sourceNameForUrl = historyItem ? historyItem.sourceName : (new URLSearchParams(new URL(url, window.location.origin).search)).get('source'); const sourceCodeForUrl = historyItem ? historyItem.sourceCode || historyItem.sourceName : (new URLSearchParams(new URL(url, window.location.origin).search)).get('source_code'); const idForUrl = historyItem ? historyItem.vod_id : ''; if (url.includes('player.html') || url.includes('watch.html')) { // console.log('检测到嵌套播放链接,解析真实URL'); try { const nestedUrl = new URL(url, window.location.origin); const nestedParams = nestedUrl.searchParams; const realVideoUrl = nestedParams.get('url') || url; playerUrl = `player.html?url=${encodeURIComponent(realVideoUrl)}&title=${encodeURIComponent(title)}&index=${episodeIndex}&position=${Math.floor(playbackPosition || 0)}&returnUrl=${encodeURIComponent(currentPath)}`; if (sourceNameForUrl) playerUrl += `&source=${encodeURIComponent(sourceNameForUrl)}`; if (sourceCodeForUrl) playerUrl += `&source_code=${encodeURIComponent(sourceCodeForUrl)}`; if (idForUrl) playerUrl += `&id=${encodeURIComponent(idForUrl)}`; } catch (e) { // console.error('解析嵌套URL出错:', e); playerUrl = `player.html?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}&index=${episodeIndex}&position=${Math.floor(playbackPosition || 0)}&returnUrl=${encodeURIComponent(currentPath)}`; if (sourceNameForUrl) playerUrl += `&source=${encodeURIComponent(sourceNameForUrl)}`; if (sourceCodeForUrl) playerUrl += `&source_code=${encodeURIComponent(sourceCodeForUrl)}`; if (idForUrl) playerUrl += `&id=${encodeURIComponent(idForUrl)}`; } } else { // This case should ideally not happen if 'url' is always a player.html link from history // console.warn("Playing from history with a non-player.html URL structure. This might be an issue."); const playUrl = new URL(url, window.location.origin); if (!playUrl.searchParams.has('index') && episodeIndex > 0) { playUrl.searchParams.set('index', episodeIndex); } playUrl.searchParams.set('position', Math.floor(playbackPosition || 0).toString()); playUrl.searchParams.set('returnUrl', encodeURIComponent(currentPath)); if (sourceNameForUrl) playUrl.searchParams.set('source', sourceNameForUrl); if (sourceCodeForUrl) playUrl.searchParams.set('source_code', sourceCodeForUrl); if (idForUrl) playUrl.searchParams.set('id', idForUrl); playerUrl = playUrl.toString(); } showVideoPlayer(playerUrl); } catch (e) { // console.error('从历史记录播放失败:', e); const simpleUrl = `player.html?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}&index=${episodeIndex}`; showVideoPlayer(simpleUrl); } } // 添加观看历史 - 确保每个视频标题只有一条记录 // IMPORTANT: videoInfo passed to this function should include a 'showIdentifier' property // (ideally `${sourceName}_${vod_id}`), 'sourceName', and 'vod_id'. function addToViewingHistory(videoInfo) { // 密码保护校验 if (window.isPasswordProtected && window.isPasswordVerified) { if (window.isPasswordProtected() && !window.isPasswordVerified()) { showPasswordModal && showPasswordModal(); return; } } try { const history = getViewingHistory(); // Ensure videoInfo has a showIdentifier if (!videoInfo.showIdentifier) { if (videoInfo.sourceName && videoInfo.vod_id) { videoInfo.showIdentifier = `${videoInfo.sourceName}_${videoInfo.vod_id}`; } else { // Fallback if critical IDs are missing for the preferred identifier videoInfo.showIdentifier = (videoInfo.episodes && videoInfo.episodes.length > 0) ? videoInfo.episodes[0] : videoInfo.directVideoUrl; // console.warn(`addToViewingHistory: videoInfo for "${videoInfo.title}" was missing sourceName or vod_id for preferred showIdentifier. Generated fallback: ${videoInfo.showIdentifier}`); } } const existingIndex = history.findIndex(item => item.title === videoInfo.title && item.sourceName === videoInfo.sourceName && item.showIdentifier === videoInfo.showIdentifier // Strict check using the determined showIdentifier ); if (existingIndex !== -1) { // Exact match with showIdentifier: Update existing series entry const existingItem = history[existingIndex]; existingItem.episodeIndex = videoInfo.episodeIndex; existingItem.timestamp = Date.now(); existingItem.sourceName = videoInfo.sourceName || existingItem.sourceName; existingItem.sourceCode = videoInfo.sourceCode || existingItem.sourceCode; existingItem.vod_id = videoInfo.vod_id || existingItem.vod_id; existingItem.directVideoUrl = videoInfo.directVideoUrl || existingItem.directVideoUrl; existingItem.url = videoInfo.url || existingItem.url; existingItem.playbackPosition = videoInfo.playbackPosition > 10 ? videoInfo.playbackPosition : (existingItem.playbackPosition || 0); existingItem.duration = videoInfo.duration || existingItem.duration; if (videoInfo.episodes && Array.isArray(videoInfo.episodes) && videoInfo.episodes.length > 0) { if (!existingItem.episodes || !Array.isArray(existingItem.episodes) || existingItem.episodes.length !== videoInfo.episodes.length || !videoInfo.episodes.every((ep, i) => ep === existingItem.episodes[i])) { existingItem.episodes = [...videoInfo.episodes]; // console.log(`更新 (addToViewingHistory) "${videoInfo.title}" 的剧集数据: ${videoInfo.episodes.length}集`); } } history.splice(existingIndex, 1); history.unshift(existingItem); // console.log(`更新历史记录 (addToViewingHistory): "${videoInfo.title}", 第 ${videoInfo.episodeIndex !== undefined ? videoInfo.episodeIndex + 1 : 'N/A'} 集`); } else { // No exact match: Add as a new entry const newItem = { ...videoInfo, // Includes the showIdentifier we ensured is present timestamp: Date.now() }; if (videoInfo.episodes && Array.isArray(videoInfo.episodes)) { newItem.episodes = [...videoInfo.episodes]; } else { newItem.episodes = []; } history.unshift(newItem); // console.log(`创建新的历史记录 (addToViewingHistory): "${videoInfo.title}", Episode: ${videoInfo.episodeIndex !== undefined ? videoInfo.episodeIndex + 1 : 'N/A'}`); } // 限制历史记录数量为50条 const maxHistoryItems = 50; if (history.length > maxHistoryItems) { history.splice(maxHistoryItems); } // 保存到本地存储 localStorage.setItem('viewingHistory', JSON.stringify(history)); } catch (e) { // console.error('保存观看历史失败:', e); } } // 清空观看历史 function clearViewingHistory() { try { localStorage.removeItem('viewingHistory'); loadViewingHistory(); // 重新加载空的历史记录 showToast('观看历史已清空', 'success'); } catch (e) { // console.error('清除观看历史失败:', e); showToast('清除观看历史失败', 'error'); } } // 更新toggleSettings函数以处理历史面板互动 const originalToggleSettings = toggleSettings; toggleSettings = function(e) { if (e) e.stopPropagation(); // 原始设置面板切换逻辑 originalToggleSettings(e); // 如果历史记录面板是打开的,则关闭它 const historyPanel = document.getElementById('historyPanel'); if (historyPanel && historyPanel.classList.contains('show')) { historyPanel.classList.remove('show'); } }; // 点击外部关闭历史面板 document.addEventListener('DOMContentLoaded', function() { document.addEventListener('click', function(e) { const historyPanel = document.getElementById('historyPanel'); const historyButton = document.querySelector('button[onclick="toggleHistory(event)"]'); if (historyPanel && historyButton && !historyPanel.contains(e.target) && !historyButton.contains(e.target) && historyPanel.classList.contains('show')) { historyPanel.classList.remove('show'); } }); }); // 清除本地存储缓存并刷新页面 function clearLocalStorage() { // 确保模态框在页面上只有一个实例 let modal = document.getElementById('messageBoxModal'); if (modal) { document.body.removeChild(modal); } // 创建模态框元素 modal = document.createElement('div'); modal.id = 'messageBoxModal'; modal.className = 'fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-40'; modal.innerHTML = `

警告

确定要清除页面缓存吗?
此功能会删除你的观看记录、自定义 API 接口和 Cookie,此操作不可恢复!
`; // 添加模态框到页面 document.body.appendChild(modal); // 添加事件监听器 - 关闭按钮 document.getElementById('closeBoxModal').addEventListener('click', function () { document.body.removeChild(modal); }); // 添加事件监听器 - 确定按钮 document.getElementById('confirmBoxModal').addEventListener('click', function () { // 清除所有localStorage数据 localStorage.clear(); // 清除所有cookie const cookies = document.cookie.split(";"); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i]; const eqPos = cookie.indexOf("="); const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim(); document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/"; } modal.innerHTML = `

提示

页面缓存和Cookie已清除,3 秒后自动刷新本页面。
`; let countdown = 3; const countdownElement = document.getElementById('countdown'); const countdownInterval = setInterval(() => { countdown--; if (countdown >= 0) { countdownElement.textContent = countdown; } else { clearInterval(countdownInterval); window.location.reload(); } }, 1000); }); // 添加事件监听器 - 取消按钮 document.getElementById('cancelBoxModal').addEventListener('click', function () { document.body.removeChild(modal); }); // 添加事件监听器 - 点击模态框外部关闭 modal.addEventListener('click', function (e) { if (e.target === modal) { document.body.removeChild(modal); } }); } // 显示配置文件导入页面 function showImportBox(fun) { // 确保模态框在页面上只有一个实例 let modal = document.getElementById('showImportBoxModal'); if (modal) { document.body.removeChild(modal); } // 创建模态框元素 modal = document.createElement('div'); modal.id = 'showImportBoxModal'; modal.className = 'fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-40'; modal.innerHTML = `

将配置文件拖到此处,或手动选择文件

`; // 添加模态框到页面 document.body.appendChild(modal); // 添加事件监听器 - 关闭按钮 document.getElementById('closeBoxModal').addEventListener('click', function () { document.body.removeChild(modal); }); // 添加事件监听器 - 点击模态框外部关闭 modal.addEventListener('click', function (e) { if (e.target === modal) { document.body.removeChild(modal); } }); // 添加事件监听器 - 拖拽文件 const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('ChooseFile'); dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('border-blue-500'); }); dropZone.addEventListener('dragleave', () => { dropZone.classList.remove('border-blue-500'); }); dropZone.addEventListener('drop', (e) => { e.preventDefault(); fun(e.dataTransfer.files[0]); }); fileInput.addEventListener('change', (e) => { fun(fileInput.files[0]); }); }