From b3ae78c75a3de1bdfed8f9d7488993e29f52be25 Mon Sep 17 00:00:00 2001 From: MaJiangla <2652352927@qq.com> Date: Fri, 13 Feb 2026 20:55:08 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=AD=E5=9B=BD?= =?UTF-8?q?=E7=89=88=E5=A3=81=E7=BA=B8API=E5=B9=B6=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BB=8A=E6=97=A5=E5=A3=81=E7=BA=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 135 ++++++++++++++++++++----------------- script.js | 184 +++++++++++++++++++++++++-------------------------- wallpaper.js | 124 +++++++++++++++++----------------- 3 files changed, 230 insertions(+), 213 deletions(-) diff --git a/README.md b/README.md index de8c3ed..cd72333 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,75 @@ -# RandomWord - 英语单词动态壁纸 - -[![AGPL-3.0 License](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) -[![Lively Wallpaper](https://img.shields.io/badge/Lively-Compatible-green.svg)](https://github.com/rocksdanister/lively) -[![dict API](https://img.shields.io/badge/dict-API-blue.svg)](https://github.com/kajweb/dict) - -在精美壁纸上学习英语单词的动态壁纸应用,支持 Lively Wallpaper。 - -[在线预览](https://majiangla.github.io/RandomWord/) - -## ✨ 功能特色 - -- 📚 内置高中/四级词库,支持自定义 CSV 导入 -- 🎨 智能主题色提取,从壁纸自动配色 -- 📍 可调卡片位置(横纵百分比) -- 🔄 自动切换单词和壁纸 -- 🌄 必应每日壁纸(国际版/中国版双源) - -## 🚀 快速使用 - -**本地运行:** -```bash -git clone https://github.com/majiangla/RandomWord.git -cd RandomWord -python -m http.server 8000 -``` -访问 `http://localhost:8000` - -**Lively 壁纸:** -1. [下载 Release](https://github.com/majiangla/RandomWord/releases/tag/pnblish) -2. 拖入 Lively Wallpaper 窗口 - -## ⚙️ 基本设置 - -1. **词书选择**:高中/四级或自定义 CSV -2. **位置调整**:水平/垂直滑块 (0-100%) -3. **显示控制**:单词/释义开关,动画开关 -4. **自动模式**:设置切换间隔时间 - -## 📄 词书格式 - -```csv -单词,释义 -apple,苹果 -book,书 -computer,计算机 -``` - -## 🤝 致谢 - -- [bing-wallpaper](https://github.com/niumoo/bing-wallpaper) - 壁纸数据 -- [dict](https://github.com/kajweb/dict) - 词典数据 - -## 📄 许可证 - -AGPL-3.0 © [MaJiang](https://github.com/majiangla) - ---- - -⭐ **欢迎 Star 和 Fork!** +# RandomWord - 英语单词动态壁纸 + +[![AGPL-3.0 License](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) +[![Lively Wallpaper](https://img.shields.io/badge/Lively-Compatible-green.svg)](https://github.com/rocksdanister/lively) +[![dict API](https://img.shields.io/badge/dict-API-blue.svg)](https://github.com/kajweb/dict) + +在精美壁纸上学习英语单词的动态壁纸应用,支持 Lively Wallpaper。 + +[在线预览](https://majiangla.github.io/RandomWord/) + +## ✨ 功能特色 + +- 📚 内置高中/四级词库,支持自定义 CSV 导入 +- 🎨 智能主题色提取,从壁纸自动配色 +- 📍 可调卡片位置(横纵百分比) +- 🔄 自动切换单词和壁纸 +- 🌄 必应每日壁纸(中国版新 API + 国际版 GitHub 数据) + +## 🚀 快速使用 + +**本地运行:** +```bash +git clone https://github.com/majiangla/RandomWord.git +cd RandomWord +python -m http.server 8000 +``` +访问 `http://localhost:8000` + +**Lively 壁纸:** +1. [下载 Release](https://github.com/majiangla/RandomWord/releases/tag/pnblish) +2. 拖入 Lively Wallpaper 窗口 + +## ⚙️ 基本设置 + +1. **词书选择**:高中/四级或自定义 CSV +2. **位置调整**:水平/垂直滑块 (0-100%) +3. **显示控制**:单词/释义开关,动画开关 +4. **自动模式**:设置切换间隔时间 + + +## 🖼️ 中国版 Bing 壁纸开放 API + +本站中国版壁纸使用以下可直接引用的图片 API: + +- 今日壁纸(长期服务):`https://bing.img.run/uhd.php` +- 随机历史壁纸:`https://bing.img.run/rand_uhd.php`(收录范围:2020-09-01 至今) + +可直接作为 `img` 链接使用: + +```html +Bing每日壁纸UHD超高清原图 +随机获取Bing历史壁纸UHD超高清原图 +``` + +## 📄 词书格式 + +```csv +单词,释义 +apple,苹果 +book,书 +computer,计算机 +``` + +## 🤝 致谢 + +- [bing-wallpaper](https://github.com/niumoo/bing-wallpaper) - 壁纸数据 +- [dict](https://github.com/kajweb/dict) - 词典数据 + +## 📄 许可证 + +AGPL-3.0 © [MaJiang](https://github.com/majiangla) + +--- + +⭐ **欢迎 Star 和 Fork!** diff --git a/script.js b/script.js index 30fff92..ea61b7e 100644 --- a/script.js +++ b/script.js @@ -1,93 +1,93 @@ -// 主应用程序 -class VocabularyApp { - constructor() { - // 初始化模块 - this.wordManager = new WordManager(); - this.wallpaperManager = new WallpaperManager(); - this.settingsManager = new SettingsManager(this.wordManager, this.wallpaperManager); - - // 全局状态 - this.isInitialized = false; - } - - // 初始化应用程序 - async init() { - if (this.isInitialized) return; - - // 显示启动信息 - this.showWelcomeMessage(); - - // 初始化UI - this.settingsManager.initUIElements(); - - // 尝试自动加载词书 - const hasWords = await this.wordManager.tryAutoLoad(); - - // 显示随机单词 - this.showRandomWord(); - - // 设置壁纸 - this.wallpaperManager.setRandomBingBackground(); - - // 设置全局事件监听 - this.setupGlobalEventListeners(); - - this.isInitialized = true; - Logger.log('应用程序初始化完成'); - } - - // 显示欢迎信息 - showWelcomeMessage() { - console.log('===================================='); - console.log('MaJiang - 英语单词随机展示系统'); - console.log('作者: MaJiangla (Bilibili: 1431497051)'); - console.log('功能说明:'); - console.log(' • 点击页面任意位置切换单词'); - console.log(' • 每 ' + this.settingsManager.settings.bgInterval + ' 个单词切换一次壁纸'); - console.log(' • 支持导入CSV格式单词表'); - console.log(' • 支持自动模式'); - console.log(' • 支持词书选择'); - console.log('===================================='); - } - - // 设置全局事件监听器 - setupGlobalEventListeners() { - // 点击页面切换单词 - document.body.addEventListener('click', (e) => { - if (!this.settingsManager.elements.settingsMenu.contains(e.target) && - !this.settingsManager.elements.settingsBtn.contains(e.target)) { - this.showRandomWord(); - } - }); - } - - // 显示随机单词 - showRandomWord() { - const entry = this.wordManager.showRandom(); - - // 更新显示 - this.settingsManager.updateDisplay(entry.word, entry.meaning); - - // 记录日志 - Logger.logWord(entry.word, entry.meaning ? entry.meaning.replace(/\n/g, ' ') : '(无释义)'); - - // 增加点击计数 - this.settingsManager.incrementClickCount(); - } -} - -// 创建全局实例 -let app; - -// 将showRandomWord暴露为全局函数(提前定义,避免空闲检测时未定义) -window.showRandomWord = () => { - if (app && typeof app.showRandomWord === 'function') { - app.showRandomWord(); - } -}; - -// 页面加载完成后初始化 -window.onload = async function() { - app = new VocabularyApp(); - await app.init(); +// 主应用程序 +class VocabularyApp { + constructor() { + // 初始化模块 + this.wordManager = new WordManager(); + this.wallpaperManager = new WallpaperManager(); + this.settingsManager = new SettingsManager(this.wordManager, this.wallpaperManager); + + // 全局状态 + this.isInitialized = false; + } + + // 初始化应用程序 + async init() { + if (this.isInitialized) return; + + // 显示启动信息 + this.showWelcomeMessage(); + + // 初始化UI + this.settingsManager.initUIElements(); + + // 尝试自动加载词书 + const hasWords = await this.wordManager.tryAutoLoad(); + + // 显示随机单词 + this.showRandomWord(); + + // 设置壁纸(初始化固定为中国版必应今日壁纸) + this.wallpaperManager.setChineseDailyBackground(); + + // 设置全局事件监听 + this.setupGlobalEventListeners(); + + this.isInitialized = true; + Logger.log('应用程序初始化完成'); + } + + // 显示欢迎信息 + showWelcomeMessage() { + console.log('===================================='); + console.log('MaJiang - 英语单词随机展示系统'); + console.log('作者: MaJiangla (Bilibili: 1431497051)'); + console.log('功能说明:'); + console.log(' • 点击页面任意位置切换单词'); + console.log(' • 每 ' + this.settingsManager.settings.bgInterval + ' 个单词切换一次壁纸'); + console.log(' • 支持导入CSV格式单词表'); + console.log(' • 支持自动模式'); + console.log(' • 支持词书选择'); + console.log('===================================='); + } + + // 设置全局事件监听器 + setupGlobalEventListeners() { + // 点击页面切换单词 + document.body.addEventListener('click', (e) => { + if (!this.settingsManager.elements.settingsMenu.contains(e.target) && + !this.settingsManager.elements.settingsBtn.contains(e.target)) { + this.showRandomWord(); + } + }); + } + + // 显示随机单词 + showRandomWord() { + const entry = this.wordManager.showRandom(); + + // 更新显示 + this.settingsManager.updateDisplay(entry.word, entry.meaning); + + // 记录日志 + Logger.logWord(entry.word, entry.meaning ? entry.meaning.replace(/\n/g, ' ') : '(无释义)'); + + // 增加点击计数 + this.settingsManager.incrementClickCount(); + } +} + +// 创建全局实例 +let app; + +// 将showRandomWord暴露为全局函数(提前定义,避免空闲检测时未定义) +window.showRandomWord = () => { + if (app && typeof app.showRandomWord === 'function') { + app.showRandomWord(); + } +}; + +// 页面加载完成后初始化 +window.onload = async function() { + app = new VocabularyApp(); + await app.init(); }; \ No newline at end of file diff --git a/wallpaper.js b/wallpaper.js index b144f07..5aeb411 100644 --- a/wallpaper.js +++ b/wallpaper.js @@ -1,11 +1,49 @@ // 壁纸管理模块 class WallpaperManager { - constructor() { - this.currentWallpaperUrl = ''; - this.currentThemeColor = CONSTANTS.DEFAULT_THEME_COLOR; - this.isChangingBg = false; - this.wallPaperSources = JSON.parse(JSON.stringify(CONSTANTS.WALLPAPER_SOURCES)); - } + constructor() { + this.currentWallpaperUrl = ''; + this.currentWallpaperApiUrl = ''; + this.currentThemeColor = CONSTANTS.DEFAULT_THEME_COLOR; + this.isChangingBg = false; + this.wallPaperSources = JSON.parse(JSON.stringify(CONSTANTS.WALLPAPER_SOURCES)); + } + + // 设置中国版今日壁纸(初始化用) + setChineseDailyBackground() { + const dailyWallpaperUrl = 'https://bing.img.run/uhd.php'; + this.currentWallpaperApiUrl = dailyWallpaperUrl; + this.loadAndApplyWallpaper(dailyWallpaperUrl, dailyWallpaperUrl); + } + + // 加载并应用壁纸 + loadAndApplyWallpaper(imageUrl, downloadUrl = imageUrl) { + this.currentWallpaperUrl = downloadUrl; + + const img = new Image(); + img.crossOrigin = 'anonymous'; + + img.onload = () => { + try { + const avgColor = this.getImageAverageColor(img); + if (avgColor) { + this.applyThemeColor(avgColor); + } else { + Logger.logError('无法获取平均色,保持当前主题色'); + } + } catch (e) { + Logger.logError(`更新主题色失败: ${e.message}`); + } + + this.applyWallpaperTransition(imageUrl); + }; + + img.onerror = () => { + Logger.logError('壁纸加载失败,保持当前背景和主题'); + this.isChangingBg = false; + }; + + img.src = imageUrl; + } // 获取图片平均颜色 getImageAverageColor(img) { @@ -98,8 +136,8 @@ class WallpaperManager { this.isChangingBg = true; - try { - Logger.log('正在获取壁纸...'); + try { + Logger.log('正在获取壁纸...'); const enabledSources = []; if (this.wallPaperSources.international.enabled) enabledSources.push('international'); @@ -115,29 +153,17 @@ class WallpaperManager { const source = this.wallPaperSources[randomSource]; const isChinese = randomSource === 'chinese'; - let githubUrl = ''; - const now = new Date(); - const currentYear = now.getFullYear(); - const currentMonth = now.getMonth() + 1; - - if (isChinese) { - let randomYear, randomMonth; - if (currentYear === source.startYear) { - randomMonth = Math.floor(Math.random() * (currentMonth - source.startMonth + 1)) + source.startMonth; - randomYear = currentYear; - } else { - const totalMonths = (currentYear - source.startYear) * 12 + currentMonth - source.startMonth; - const randomOffset = Math.floor(Math.random() * (totalMonths + 1)); - randomYear = source.startYear + Math.floor(randomOffset / 12); - randomMonth = source.startMonth + (randomOffset % 12); - - if (randomYear === currentYear && randomMonth > currentMonth) { - randomMonth = currentMonth; - } - } - - githubUrl = `https://raw.githubusercontent.com/niumoo/bing-wallpaper/refs/heads/main/zh-cn/picture/${randomYear}-${String(randomMonth).padStart(2, '0')}/README.md`; - } else { + let githubUrl = ''; + const now = new Date(); + const currentYear = now.getFullYear(); + const currentMonth = now.getMonth() + 1; + + if (isChinese) { + const randomHistoryUrl = `https://bing.img.run/rand_uhd.php?t=${Date.now()}`; + this.currentWallpaperApiUrl = randomHistoryUrl; + this.loadAndApplyWallpaper(randomHistoryUrl, 'https://bing.img.run/rand_uhd.php'); + return; + } else { const randomYear = Math.floor(Math.random() * (currentYear - source.startYear + 1)) + source.startYear; let randomMonth; if (randomYear === source.startYear) { @@ -161,36 +187,12 @@ class WallpaperManager { const markdownContent = await response.text(); const wallpapers = this.parseMarkdownForWallpapers(markdownContent); - if (wallpapers.length > 0) { - const randomIndex = Math.floor(Math.random() * wallpapers.length); - const selectedWallpaper = wallpapers[randomIndex]; - this.currentWallpaperUrl = selectedWallpaper.url; - - const img = new Image(); - img.crossOrigin = "anonymous"; - - img.onload = () => { - try { - const avgColor = this.getImageAverageColor(img); - if (avgColor) { - this.applyThemeColor(avgColor); - } else { - Logger.logError('无法获取平均色,保持当前主题色'); - } - } catch (e) { - Logger.logError(`更新主题色失败: ${e.message}`); - } - - this.applyWallpaperTransition(selectedWallpaper.url); - }; - - img.onerror = () => { - Logger.logError('壁纸加载失败,保持当前背景和主题'); - this.isChangingBg = false; - }; - - img.src = selectedWallpaper.url; - } else { + if (wallpapers.length > 0) { + const randomIndex = Math.floor(Math.random() * wallpapers.length); + const selectedWallpaper = wallpapers[randomIndex]; + this.currentWallpaperApiUrl = selectedWallpaper.url; + this.loadAndApplyWallpaper(selectedWallpaper.url); + } else { Logger.logError('未找到壁纸数据,保持当前背景和主题'); this.isChangingBg = false; } From 3e5364c75f37a665e84441230a23514f6af8b960 Mon Sep 17 00:00:00 2001 From: MaJiangla <2652352927@qq.com> Date: Fri, 13 Feb 2026 23:00:40 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=AD=E5=9B=BD?= =?UTF-8?q?=E7=89=88=E5=A3=81=E7=BA=B8=E6=8E=A5=E5=8F=A3=E7=9A=84=20CORS?= =?UTF-8?q?=20=E5=8A=A0=E8=BD=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wallpaper.js | 429 ++++++++++++++++++++++++++------------------------- 1 file changed, 217 insertions(+), 212 deletions(-) diff --git a/wallpaper.js b/wallpaper.js index 5aeb411..b2395b2 100644 --- a/wallpaper.js +++ b/wallpaper.js @@ -1,5 +1,5 @@ -// 壁纸管理模块 -class WallpaperManager { +// 壁纸管理模块 +class WallpaperManager { constructor() { this.currentWallpaperUrl = ''; this.currentWallpaperApiUrl = ''; @@ -12,26 +12,31 @@ class WallpaperManager { setChineseDailyBackground() { const dailyWallpaperUrl = 'https://bing.img.run/uhd.php'; this.currentWallpaperApiUrl = dailyWallpaperUrl; - this.loadAndApplyWallpaper(dailyWallpaperUrl, dailyWallpaperUrl); + this.loadAndApplyWallpaper(dailyWallpaperUrl, dailyWallpaperUrl, { useCors: false, extractTheme: false }); } // 加载并应用壁纸 - loadAndApplyWallpaper(imageUrl, downloadUrl = imageUrl) { + loadAndApplyWallpaper(imageUrl, downloadUrl = imageUrl, options = {}) { + const { useCors = true, extractTheme = true } = options; this.currentWallpaperUrl = downloadUrl; const img = new Image(); - img.crossOrigin = 'anonymous'; + if (useCors) { + img.crossOrigin = 'anonymous'; + } img.onload = () => { - try { - const avgColor = this.getImageAverageColor(img); - if (avgColor) { - this.applyThemeColor(avgColor); - } else { - Logger.logError('无法获取平均色,保持当前主题色'); + if (extractTheme) { + try { + const avgColor = this.getImageAverageColor(img); + if (avgColor) { + this.applyThemeColor(avgColor); + } else { + Logger.logError('无法获取平均色,保持当前主题色'); + } + } catch (e) { + Logger.logError(`更新主题色失败: ${e.message}`); } - } catch (e) { - Logger.logError(`更新主题色失败: ${e.message}`); } this.applyWallpaperTransition(imageUrl); @@ -44,115 +49,115 @@ class WallpaperManager { img.src = imageUrl; } - - // 获取图片平均颜色 - getImageAverageColor(img) { - try { - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - canvas.width = 50; - canvas.height = 50; - - ctx.drawImage(img, 0, 0, 50, 50); - - const imageData = ctx.getImageData(0, 0, 50, 50); - const data = imageData.data; - - let r = 0, g = 0, b = 0; - const pixelCount = 50 * 50; - - for (let i = 0; i < data.length; i += 4) { - r += data[i]; - g += data[i + 1]; - b += data[i + 2]; - } - - r = Math.floor(r / pixelCount); - g = Math.floor(g / pixelCount); - b = Math.floor(b / pixelCount); - - Logger.log(`平均颜色: RGB(${r}, ${g}, ${b})`); - return { r, g, b }; - } catch (error) { - Logger.logError(`获取颜色失败: ${error.message}`); - return null; - } - } - - // 应用主题颜色到所有元素 - applyThemeColor(color) { - if (!color) { - Logger.log('保持当前主题颜色不变'); - return; - } - - const adjustedColor = Utils.ensureContrastWithWhite(color.r, color.g, color.b); - this.currentThemeColor = adjustedColor; - - const primaryColor = `rgb(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b})`; - const secondaryColor = `rgba(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}, 0.8)`; - const thirdColor = `rgba(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}, 0.4)`; - - document.documentElement.style.setProperty('--primary-color', primaryColor); - document.documentElement.style.setProperty('--secondary-color', secondaryColor); - document.documentElement.style.setProperty('--third-color', thirdColor); - - const whiteContrast = Utils.getContrastRatio(adjustedColor.r, adjustedColor.g, adjustedColor.b, 255, 255, 255); - Logger.log(`主题色: RGB(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}), 对比度: ${whiteContrast.toFixed(2)}`); - } - - // 更新壁纸源选择 - updateWallpaperSources(internationalChecked, chineseChecked) { - this.wallPaperSources.international.enabled = internationalChecked; - this.wallPaperSources.chinese.enabled = chineseChecked; - - if (!internationalChecked && !chineseChecked) { - this.wallPaperSources.chinese.enabled = true; - Logger.log('至少选择一个'); - return true; // 表示需要更新UI - } - return false; - } - - // 解析壁纸数据 - parseMarkdownForWallpapers(markdown) { - const wallpapers = []; - const regex = /!\[.*?\]\((.*?)\)(\d{4}-\d{2}-\d{2}) \[download 4k\]\((.*?)\)/g; - let match; - - while ((match = regex.exec(markdown)) !== null) { - const fullUrl = match[3]; - if (fullUrl && fullUrl.startsWith('http')) { - wallpapers.push({ url: fullUrl }); - } - } - - return wallpapers; - } - - // 获取随机壁纸 - async setRandomBingBackground() { - if (this.isChangingBg) return; - - this.isChangingBg = true; - + + // 获取图片平均颜色 + getImageAverageColor(img) { + try { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = 50; + canvas.height = 50; + + ctx.drawImage(img, 0, 0, 50, 50); + + const imageData = ctx.getImageData(0, 0, 50, 50); + const data = imageData.data; + + let r = 0, g = 0, b = 0; + const pixelCount = 50 * 50; + + for (let i = 0; i < data.length; i += 4) { + r += data[i]; + g += data[i + 1]; + b += data[i + 2]; + } + + r = Math.floor(r / pixelCount); + g = Math.floor(g / pixelCount); + b = Math.floor(b / pixelCount); + + Logger.log(`平均颜色: RGB(${r}, ${g}, ${b})`); + return { r, g, b }; + } catch (error) { + Logger.logError(`获取颜色失败: ${error.message}`); + return null; + } + } + + // 应用主题颜色到所有元素 + applyThemeColor(color) { + if (!color) { + Logger.log('保持当前主题颜色不变'); + return; + } + + const adjustedColor = Utils.ensureContrastWithWhite(color.r, color.g, color.b); + this.currentThemeColor = adjustedColor; + + const primaryColor = `rgb(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b})`; + const secondaryColor = `rgba(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}, 0.8)`; + const thirdColor = `rgba(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}, 0.4)`; + + document.documentElement.style.setProperty('--primary-color', primaryColor); + document.documentElement.style.setProperty('--secondary-color', secondaryColor); + document.documentElement.style.setProperty('--third-color', thirdColor); + + const whiteContrast = Utils.getContrastRatio(adjustedColor.r, adjustedColor.g, adjustedColor.b, 255, 255, 255); + Logger.log(`主题色: RGB(${adjustedColor.r}, ${adjustedColor.g}, ${adjustedColor.b}), 对比度: ${whiteContrast.toFixed(2)}`); + } + + // 更新壁纸源选择 + updateWallpaperSources(internationalChecked, chineseChecked) { + this.wallPaperSources.international.enabled = internationalChecked; + this.wallPaperSources.chinese.enabled = chineseChecked; + + if (!internationalChecked && !chineseChecked) { + this.wallPaperSources.chinese.enabled = true; + Logger.log('至少选择一个'); + return true; // 表示需要更新UI + } + return false; + } + + // 解析壁纸数据 + parseMarkdownForWallpapers(markdown) { + const wallpapers = []; + const regex = /!\[.*?\]\((.*?)\)(\d{4}-\d{2}-\d{2}) \[download 4k\]\((.*?)\)/g; + let match; + + while ((match = regex.exec(markdown)) !== null) { + const fullUrl = match[3]; + if (fullUrl && fullUrl.startsWith('http')) { + wallpapers.push({ url: fullUrl }); + } + } + + return wallpapers; + } + + // 获取随机壁纸 + async setRandomBingBackground() { + if (this.isChangingBg) return; + + this.isChangingBg = true; + try { Logger.log('正在获取壁纸...'); - - const enabledSources = []; - if (this.wallPaperSources.international.enabled) enabledSources.push('international'); - if (this.wallPaperSources.chinese.enabled) enabledSources.push('chinese'); - - if (enabledSources.length === 0) { - Logger.logError('未选择壁纸源'); - this.isChangingBg = false; - return; - } - - const randomSource = enabledSources[Math.floor(Math.random() * enabledSources.length)]; - const source = this.wallPaperSources[randomSource]; - const isChinese = randomSource === 'chinese'; - + + const enabledSources = []; + if (this.wallPaperSources.international.enabled) enabledSources.push('international'); + if (this.wallPaperSources.chinese.enabled) enabledSources.push('chinese'); + + if (enabledSources.length === 0) { + Logger.logError('未选择壁纸源'); + this.isChangingBg = false; + return; + } + + const randomSource = enabledSources[Math.floor(Math.random() * enabledSources.length)]; + const source = this.wallPaperSources[randomSource]; + const isChinese = randomSource === 'chinese'; + let githubUrl = ''; const now = new Date(); const currentYear = now.getFullYear(); @@ -161,103 +166,103 @@ class WallpaperManager { if (isChinese) { const randomHistoryUrl = `https://bing.img.run/rand_uhd.php?t=${Date.now()}`; this.currentWallpaperApiUrl = randomHistoryUrl; - this.loadAndApplyWallpaper(randomHistoryUrl, 'https://bing.img.run/rand_uhd.php'); + this.loadAndApplyWallpaper(randomHistoryUrl, 'https://bing.img.run/rand_uhd.php', { useCors: false, extractTheme: false }); return; } else { - const randomYear = Math.floor(Math.random() * (currentYear - source.startYear + 1)) + source.startYear; - let randomMonth; - if (randomYear === source.startYear) { - randomMonth = Math.floor(Math.random() * (12 - source.startMonth + 1)) + source.startMonth; - } else if (randomYear === currentYear) { - randomMonth = Math.floor(Math.random() * currentMonth) + 1; - } else { - randomMonth = Math.floor(Math.random() * 12) + 1; - } - - githubUrl = `https://raw.githubusercontent.com/niumoo/bing-wallpaper/refs/heads/main/picture/${randomYear}-${String(randomMonth).padStart(2, '0')}/README.md`; - } - - Logger.log(`请求壁纸数据: ${githubUrl}`); - const response = await fetch(githubUrl, { cache: 'no-cache' }); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - - const markdownContent = await response.text(); - const wallpapers = this.parseMarkdownForWallpapers(markdownContent); - + const randomYear = Math.floor(Math.random() * (currentYear - source.startYear + 1)) + source.startYear; + let randomMonth; + if (randomYear === source.startYear) { + randomMonth = Math.floor(Math.random() * (12 - source.startMonth + 1)) + source.startMonth; + } else if (randomYear === currentYear) { + randomMonth = Math.floor(Math.random() * currentMonth) + 1; + } else { + randomMonth = Math.floor(Math.random() * 12) + 1; + } + + githubUrl = `https://raw.githubusercontent.com/niumoo/bing-wallpaper/refs/heads/main/picture/${randomYear}-${String(randomMonth).padStart(2, '0')}/README.md`; + } + + Logger.log(`请求壁纸数据: ${githubUrl}`); + const response = await fetch(githubUrl, { cache: 'no-cache' }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const markdownContent = await response.text(); + const wallpapers = this.parseMarkdownForWallpapers(markdownContent); + if (wallpapers.length > 0) { const randomIndex = Math.floor(Math.random() * wallpapers.length); const selectedWallpaper = wallpapers[randomIndex]; this.currentWallpaperApiUrl = selectedWallpaper.url; this.loadAndApplyWallpaper(selectedWallpaper.url); } else { - Logger.logError('未找到壁纸数据,保持当前背景和主题'); - this.isChangingBg = false; - } - - } catch (error) { - Logger.logError(`设置随机壁纸失败: ${error.message}`); - this.isChangingBg = false; - } - } - - // 应用壁纸过渡 - applyWallpaperTransition(url) { - const currentBg = document.getElementById('current-bg'); - const newBg = document.getElementById('new-bg'); - - newBg.style.backgroundImage = `url('${url}')`; - newBg.classList.remove('fade-in'); - void newBg.offsetWidth; - newBg.classList.add('fade-in'); - newBg.style.opacity = '1'; - - setTimeout(() => { - currentBg.style.backgroundImage = newBg.style.backgroundImage; - - setTimeout(() => { - newBg.style.opacity = '0'; - newBg.style.backgroundImage = ''; - Logger.logWallpaper(this.currentWallpaperUrl); - this.isChangingBg = false; - }, 100); - }, 200); - } - - // 下载当前壁纸 - async downloadCurrentWallpaper() { - if (!this.currentWallpaperUrl) { - Logger.logError('无当前壁纸可下载'); - return; - } - - try { - Logger.log('开始下载当前壁纸...'); - const response = await fetch(this.currentWallpaperUrl); - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - - const blob = await response.blob(); - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `bing-wallpaper-${new Date().toISOString().slice(0,10)}.jpg`; - - document.body.appendChild(a); - a.click(); - - setTimeout(() => { - window.URL.revokeObjectURL(url); - document.body.removeChild(a); - }, 100); - - Logger.logSuccess('壁纸下载完成'); - } catch (error) { - Logger.logError(`壁纸下载失败: ${error.message}`); - } - } - -} + Logger.logError('未找到壁纸数据,保持当前背景和主题'); + this.isChangingBg = false; + } + + } catch (error) { + Logger.logError(`设置随机壁纸失败: ${error.message}`); + this.isChangingBg = false; + } + } + + // 应用壁纸过渡 + applyWallpaperTransition(url) { + const currentBg = document.getElementById('current-bg'); + const newBg = document.getElementById('new-bg'); + + newBg.style.backgroundImage = `url('${url}')`; + newBg.classList.remove('fade-in'); + void newBg.offsetWidth; + newBg.classList.add('fade-in'); + newBg.style.opacity = '1'; + + setTimeout(() => { + currentBg.style.backgroundImage = newBg.style.backgroundImage; + + setTimeout(() => { + newBg.style.opacity = '0'; + newBg.style.backgroundImage = ''; + Logger.logWallpaper(this.currentWallpaperUrl); + this.isChangingBg = false; + }, 100); + }, 200); + } + + // 下载当前壁纸 + async downloadCurrentWallpaper() { + if (!this.currentWallpaperUrl) { + Logger.logError('无当前壁纸可下载'); + return; + } + + try { + Logger.log('开始下载当前壁纸...'); + const response = await fetch(this.currentWallpaperUrl); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `bing-wallpaper-${new Date().toISOString().slice(0,10)}.jpg`; + + document.body.appendChild(a); + a.click(); + + setTimeout(() => { + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + }, 100); + + Logger.logSuccess('壁纸下载完成'); + } catch (error) { + Logger.logError(`壁纸下载失败: ${error.message}`); + } + } + +}