您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在首页添加配置按钮, 配置首页样式
// ==UserScript== // @name 必应首页自定义背景图片 // @namespace http://tampermonkey.net/ // @version 1.0.9 // @description 在首页添加配置按钮, 配置首页样式 // @author Ctory-Nily // @match https://www.bing.com/* // @match https://cn.bing.com/* // @match https://www.bing.com/ // @match https://cn.bing.com/ // @exclude https://www.bing.com/search* // @exclude https://cn.bing.com/search* // @exclude https://www.bing.com/account* // @exclude https://cn.bing.com/account* // @icon https://www.google.com/s2/favicons?sz=64&domain=bing.com // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; // 等待页面加载完成 function waitForPageLoad() { return new Promise(resolve => { if (document.readyState === 'complete') { resolve(); } else { window.addEventListener('load', resolve); } }); } // 配置存储 const CONFIG_KEY = 'bingBackgroundConfig'; const POSITION_KEY = 'bingButtonPosition'; const BG_IMAGE_KEY = 'bingCustomBackground'; // localStorage中的背景图片key // 默认配置 const defaultConfig = { removehpTriviaOuter: true, removemusCard: true, removeVsDefault: true, removeFooter: true, theme: 'system' }; // 默认按钮位置 const defaultPosition = { left: '10px', top: 'auto', bottom: '10px', right: 'auto' }; // 获取当前配置 function getConfig() { const saved = GM_getValue(CONFIG_KEY, JSON.stringify(defaultConfig)); return JSON.parse(saved); } // 获取按钮位置 function getButtonPosition() { const saved = GM_getValue(POSITION_KEY, JSON.stringify(defaultPosition)); return JSON.parse(saved); } // 保存配置 function saveConfig(config) { GM_setValue(CONFIG_KEY, JSON.stringify(config)); applyConfig(config); } // 保存按钮位置 function saveButtonPosition(position) { GM_setValue(POSITION_KEY, JSON.stringify(position)); } // 获取背景图片 function getBackgroundImage() { return localStorage.getItem(BG_IMAGE_KEY) || ''; } // 保存背景图片 function saveBackgroundImage(imageUrl) { if (imageUrl) { localStorage.setItem(BG_IMAGE_KEY, imageUrl); } else { localStorage.removeItem(BG_IMAGE_KEY); } } // 应用配置 function applyConfig(config) { applyTheme(config.theme); const bgImage = getBackgroundImage(); const imgCont = document.querySelector('.img_cont'); const hpTopCover = document.querySelector('.hp_top_cover'); if (bgImage) { if (imgCont) imgCont.style.backgroundImage = `url("${bgImage}")`; if (hpTopCover) hpTopCover.style.backgroundImage = `url("${bgImage}")`; } if (config.removehpTriviaOuter) { const musCard = document.querySelector('.musCard'); if (musCard) musCard.remove(); } if (config.removemusCard) { const hpTriviaOuter = document.querySelector('.hp_trivia_outer'); if (hpTriviaOuter) hpTriviaOuter.remove(); } if (config.removeVsDefault) { const vsDefault = document.getElementById('vs_default'); if (vsDefault) vsDefault.remove(); } if (config.removeFooter) { const footer = document.getElementById('footer'); if (footer) footer.remove(); } updateScrollContStyle(config.removemusCard); } // 应用主题 function applyTheme(theme) { const root = document.documentElement; root.classList.remove('bing-theme-light', 'bing-theme-dark'); let effectiveTheme = theme; if (theme === 'system') { effectiveTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } if (effectiveTheme === 'dark') { root.classList.add('bing-theme-dark'); } else { root.classList.add('bing-theme-light'); } } // 更新scroll_cont样式 function updateScrollContStyle(removemusCard) { const scrollCont = document.getElementById('scroll_cont'); if (scrollCont) { scrollCont.style.marginTop = removemusCard ? '47px' : ''; } } // 添加CSS样式 GM_addStyle(` :root.bing-theme-light { --bing-primary-color: #0078d4; --bing-bg-color: #ffffff; --bing-text-color: #000000; --bing-panel-bg: rgba(255, 255, 255, 0.95); --bing-panel-text: #333333; --bing-btn-hover: rgba(0, 0, 0, 0.1); } :root.bing-theme-dark { --bing-primary-color: #0078d4; --bing-bg-color: #1e1e1e; --bing-text-color: #ffffff; --bing-panel-bg: rgba(30, 30, 30, 0.95); --bing-panel-text: #ffffff; --bing-btn-hover: rgba(255, 255, 255, 0.1); } .bing-settings-btn { position: fixed; z-index: 99999; width: 40px; height: 40px; background: var(--bing-primary-color); border: none; border-radius: 50%; cursor: move; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; touch-action: none; user-select: none; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .bing-settings-btn:hover { background: #565656; transform: scale(1.1); } .bing-settings-btn.dragging { opacity: 0.8; transform: scale(1.1); cursor: grabbing; } .bing-settings-btn.panel-open { cursor: default; } .bing-settings-icon { width: 24px; height: 24px; color: white; pointer-events: none; } .bing-settings-panel { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 100001; width: 80%; max-width: 400px; max-height: 90vh; overflow-y: auto; background: var(--bing-panel-bg); border-radius: 8px; padding: 15px; font-size: 14px; color: var(--bing-panel-text); font-family: 'Segoe UI', sans-serif; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); display: none; backdrop-filter: blur(10px); } .bing-settings-panel h3 { margin: 0 0 20px 0; font-size: 18px; text-align: center; border-bottom: 1px solid rgba(0, 0, 0, 0.1); padding-bottom: 10px; display: flex; align-items: center; justify-content: center; } .bing-settings-section { margin-bottom: 20px; } .bing-settings-section h4 { margin: 0 0 10px 0; font-size: 15px; } .bing-settings-option { display: flex; align-items: center; margin-bottom: 12px; } .bing-settings-option label { cursor: pointer; } .bing-settings-option input[type="checkbox"], .bing-settings-option select { margin-right: 10px; } .bing-settings-option button { padding: 5px; } .bing-settings-btn-group { display: flex; gap: 10px; margin-top: 20px; } .bing-settings-btn-group button { flex: 1; padding: 10px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background 0.2s; } .bing-settings-btn-primary { background: var(--bing-primary-color); color: white; } .bing-settings-btn-primary:hover { background: #106ebe; } .bing-settings-btn-secondary { background: var(--bing-btn-hover); color: var(--bing-panel-text); } .bing-settings-btn-secondary:hover { background: rgba(0, 0, 0, 0.2); } #bingBgFileInput { display: none; } .bing-theme-selector { padding: 8px 12px; border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.1); background: var(--bing-panel-bg); color: var(--bing-panel-text); font-size: 14px; width: 100%; } .bing-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); z-index: 100000; display: none; } /* 添加这些样式到你的GM_addStyle部分 */ .bing-settings-row { display: flex; align-items: center; gap: 15px; margin-bottom: 15px; } .bing-settings-row h4 { margin: 0; min-width: 80px; /* 给标题固定宽度保持对齐 */ } .bing-theme-selector { flex: 1; } .bing-button-group { display: flex; gap: 10px; flex: 1; } .bing-settings-btn-secondary { flex: 1; white-space: nowrap; } .bing-switch { position: relative; display: inline-block; width: 50px; height: 24px; margin-right: 10px; vertical-align: middle; } .bing-switch input { display: none; } .bing-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 24px; } .bing-slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 2px; bottom: 2px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .bing-slider { background-color: #0078d4 !important; } input:checked + .bing-slider:before { transform: translateX(26px); } /* 暗色主题适配 */ :root.bing-theme-dark .bing-slider { background-color: #555; } /* 调整选项布局 */ .bing-settings-option { display: flex; align-items: center; margin-bottom: 12px; } /* 主题切换按钮样式 */ .bing-theme-toggle { background: none; border: none; cursor: pointer; padding: 5px; margin-right: 10px; display: flex; align-items: center; justify-content: center; color: var(--bing-panel-text); } .bing-theme-toggle svg { width: 20px; height: 20px; fill: currentColor; } .bing-theme-toggle:hover { opacity: 0.8; } .bing-title-container { display: flex; align-items: center; justify-content: center; } /* 响应式调整 */ @media (max-width: 600px) { .bing-settings-row { flex-direction: column; align-items: flex-start; gap: 8px; } .bing-setting-mobile-row { flex-direction: row !important; align-items: center; } .bing-settings-row h4 { min-width: auto; } .bing-button-group { width: 100%; flex-direction: column; } .bing-theme-selector, .bing-settings-btn-secondary { width: 100%; line-height: 30px; } } /* 添加媒体查询 */ @media (max-width: 480px) { .bing-settings-panel { width: 80%; max-height: 80vh; padding: 10px; } .bing-settings-btn-group { flex-direction: column; } .bing-settings-btn-group button { width: 100%; } .bing-settings-section h4 { font-size: 14px; } .bing-settings-btn { width: 35px; height: 35px; inset: 350px auto auto 30px; } .bing-settings-icon { width: 30px; height: 30px; } } `); // 提示窗口 function showSaveSuccess(message = "保存成功", duration = 1000) { const div = document.createElement("div"); div.innerHTML = `✔ ${message}`; div.style.position = "fixed"; div.style.top = "20%"; // 改为从顶部20%开始 div.style.left = "50%"; div.style.transform = "translate(-50%, -50%)"; div.style.zIndex = "9999"; div.style.backgroundColor = "#4caf50"; div.style.color = "white"; div.style.padding = "12px 24px"; // 减小内边距 div.style.borderRadius = "6px"; div.style.boxShadow = "0 2px 8px rgba(0, 0, 0, 0.3)"; div.style.fontSize = "16px"; // 减小字体大小 div.style.fontWeight = "bold"; div.style.opacity = "1"; div.style.transition = "opacity 0.5s ease-out"; div.style.maxWidth = "80%"; // 限制最大宽度 div.style.textAlign = "center"; div.style.wordBreak = "break-word"; // 允许换行 document.body.appendChild(div); setTimeout(() => { div.style.opacity = "0"; setTimeout(() => div.remove(), 500); }, duration); } // 创建设置按钮 function createSettingsButton() { const settingsBtn = document.createElement('button'); settingsBtn.className = 'bing-settings-btn'; settingsBtn.title = 'Bing 背景配置'; settingsBtn.innerHTML = ` <svg class="bing-settings-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"> <path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/> <circle cx="12" cy="12" r="3"/> </svg> `; const position = getButtonPosition(); Object.keys(position).forEach(key => { if (position[key] !== 'auto') { settingsBtn.style[key] = position[key]; } }); document.body.appendChild(settingsBtn); return settingsBtn; } // 设置拖动功能 function setupDrag(element) { let isDragging = false; let offsetX, offsetY; let startX, startY; let lastX = 0, lastY = 0; let velocityX = 0, velocityY = 0; let animationFrame; let allowDrag = true; // 添加事件监听 element.addEventListener('mousedown', startDrag); element.addEventListener('touchstart', startDrag, { passive: false }); function startDrag(e) { // 如果是触摸事件且有多点触控,则不处理 if (e.touches && e.touches.length > 1) return; if (!allowDrag) return; // 记录点击位置 const rect = element.getBoundingClientRect(); const clientX = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX; const clientY = e.type === 'mousedown' ? e.clientY : e.touches[0].clientY; offsetX = clientX - rect.left; offsetY = clientY - rect.top; startX = clientX; startY = clientY; lastX = clientX; lastY = clientY; // 停止任何现有的惯性动画 cancelAnimationFrame(animationFrame); velocityX = 0; velocityY = 0; // 开始拖动 isDragging = true; element.classList.add('dragging'); element.style.transition = 'none'; // 禁用过渡效果 document.body.style.userSelect = 'none'; // 防止选中文本 // 添加事件监听 document.addEventListener('mousemove', drag); document.addEventListener('touchmove', drag, { passive: false }); document.addEventListener('mouseup', stopDrag); document.addEventListener('touchend', stopDrag); } function drag(e) { // 如果是触摸事件且有多点触控,则不处理 if (e.touches && e.touches.length > 1) return; if (!isDragging) return; e.preventDefault(); // 获取当前位置 const clientX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX; const clientY = e.type === 'mousemove' ? e.clientY : e.touches[0].clientY; // 计算速度(用于惯性效果) velocityX = clientX - lastX; velocityY = clientY - lastY; lastX = clientX; lastY = clientY; // 计算新位置 let x = clientX - offsetX; let y = clientY - offsetY; // 边界约束 const maxX = window.innerWidth - element.offsetWidth; const maxY = window.innerHeight - element.offsetHeight; x = Math.max(0, Math.min(x, maxX)); y = Math.max(0, Math.min(y, maxY)); // 应用新位置 element.style.left = `${x}px`; element.style.top = `${y}px`; element.style.bottom = 'auto'; element.style.right = 'auto'; } function stopDrag(e) { if (!isDragging) return; // 清除拖动状态 isDragging = false; element.classList.remove('dragging'); document.body.style.userSelect = ''; // 移除事件监听 document.removeEventListener('mousemove', drag); document.removeEventListener('touchmove', drag); document.removeEventListener('mouseup', stopDrag); document.removeEventListener('touchend', stopDrag); // 检查是否是点击而非拖动 const clientX = e.type === 'mouseup' ? e.clientX : e.changedTouches[0].clientX; const clientY = e.type === 'mouseup' ? e.clientY : e.changedTouches[0].clientY; const movedX = Math.abs(clientX - startX); const movedY = Math.abs(clientY - startY); if (movedX < 5 && movedY < 5) { element.dispatchEvent(new MouseEvent('click')); return; } // 保存新位置 const newPosition = { left: element.style.left, top: element.style.top, bottom: element.style.bottom, right: element.style.right }; saveButtonPosition(newPosition); // 惯性效果 const animate = () => { if (Math.abs(velocityX) < 0.1 && Math.abs(velocityY) < 0.1) { element.style.transition = ''; // 恢复过渡效果 return; } let x = parseFloat(element.style.left) + velocityX; let y = parseFloat(element.style.top) + velocityY; // 边界约束 const maxX = window.innerWidth - element.offsetWidth; const maxY = window.innerHeight - element.offsetHeight; x = Math.max(0, Math.min(x, maxX)); y = Math.max(0, Math.min(y, maxY)); // 检查是否到达边界 if (x <= 0 || x >= maxX) velocityX = 0; if (y <= 0 || y >= maxY) velocityY = 0; element.style.left = `${x}px`; element.style.top = `${y}px`; element.style.bottom = 'auto'; element.style.right = 'auto'; velocityX *= 0.95; // 摩擦力 velocityY *= 0.95; animationFrame = requestAnimationFrame(animate); }; animationFrame = requestAnimationFrame(animate); } // 公开方法以控制拖动 return { setAllowDrag: (value) => { allowDrag = value; if (!value) { element.classList.remove('dragging'); isDragging = false; } } }; } // 创建设置面板 function createSettingsPanel() { // 创建遮罩层 const overlay = document.createElement('div'); overlay.className = 'bing-modal-overlay'; // 创建面板 const settingsPanel = document.createElement('div'); settingsPanel.className = 'bing-settings-panel'; settingsPanel.innerHTML = ` <h3> <button class="bing-theme-toggle" id="bingThemeToggle" title="切换主题"> <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon-icon lucide-moon"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg> </button> <span>Bing 背景配置</span> </h3> <div class="bing-settings-section"> <div class="bing-settings-row"> <h4>背景配置</h4> <div class="bing-button-group"> <button id="bingUploadBgBtn" class="bing-settings-btn-secondary">上传背景</button> <button id="bingResetBgBtn" class="bing-settings-btn-secondary">重置背景</button> </div> </div> </div> <div class="bing-settings-section"> <h4>元素配置</h4> <div class="bing-settings-option"> <label class="bing-switch"> <input type="checkbox" id="bingremovehpTriviaOuter"> <span class="bing-slider"></span> </label> <label for="bingremovehpTriviaOuter">移除问答卡片</label> </div> <div class="bing-settings-option"> <label class="bing-switch"> <input type="checkbox" id="bingremovemusCard"> <span class="bing-slider"></span> </label> <label for="bingremovemusCard">移除切换图片按钮</label> </div> <div class="bing-settings-option"> <label class="bing-switch"> <input type="checkbox" id="bingremoveVsDefault"> <span class="bing-slider"></span> </label> <label for="bingremoveVsDefault">移除设为主页按钮部分</label> </div> <div class="bing-settings-option"> <label class="bing-switch"> <input type="checkbox" id="bingremoveFooter"> <span class="bing-slider"></span> </label> <label for="bingremoveFooter">移除页脚</label> </div> </div> <div class="bing-settings-btn-group"> <button id="bingSaveConfigBtn" class="bing-settings-btn-primary">保存配置</button> <button id="bingExportConfigBtn" class="bing-settings-btn-secondary">导出配置</button> <button id="bingImportConfigBtn" class="bing-settings-btn-secondary">导入配置</button> <button id="bingResetConfigBtn" class="bing-settings-btn-secondary">重置配置</button> </div> `; // 将面板添加到遮罩层 overlay.appendChild(settingsPanel); document.body.appendChild(overlay); return { panel: settingsPanel, overlay: overlay }; } // 初始化脚本 async function init() { // 添加视口meta标签 let meta = document.querySelector('meta[name="viewport"]'); if (!meta) { meta = document.createElement('meta'); meta.name = "viewport"; meta.content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"; document.head.appendChild(meta); } // 等待页面加载完成 await waitForPageLoad(); // 创建UI元素 const settingsBtn = createSettingsButton(); const { panel: settingsPanel, overlay: modalOverlay } = createSettingsPanel(); const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.id = 'bingBgFileInput'; fileInput.accept = 'image/*'; document.body.appendChild(fileInput); // 设置拖动功能 const dragController = setupDrag(settingsBtn); // 加载配置 const currentConfig = getConfig(); // 初始化UI状态 document.getElementById('bingremovehpTriviaOuter').checked = currentConfig.removehpTriviaOuter; document.getElementById('bingremovemusCard').checked = currentConfig.removemusCard; document.getElementById('bingremoveVsDefault').checked = currentConfig.removeVsDefault; document.getElementById('bingremoveFooter').checked = currentConfig.removeFooter; // 应用配置 applyConfig(currentConfig); // 事件监听 settingsBtn.addEventListener('click', function() { modalOverlay.style.display = 'block'; settingsPanel.style.display = 'block'; settingsBtn.classList.add('panel-open'); dragController.setAllowDrag(false); }); // ESC键关闭面板 document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && modalOverlay.style.display === 'block') { closePanel(); } }); function closePanel() { modalOverlay.style.display = 'none'; settingsPanel.style.display = 'none'; settingsBtn.classList.remove('panel-open'); dragController.setAllowDrag(true); } modalOverlay.addEventListener('click', function(e) { if (e.target === modalOverlay) { closePanel(); } }); // 主题切换按钮功能 const themeToggle = document.getElementById('bingThemeToggle'); themeToggle.addEventListener('click', function() { const currentTheme = getConfig().theme; let newTheme; if (currentTheme === 'system') { newTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'light' : 'dark'; } else { newTheme = currentTheme === 'dark' ? 'light' : 'dark'; } // 更新配置 const config = getConfig(); config.theme = newTheme; saveConfig(config); // 更新图标 updateThemeToggleIcon(newTheme); applyTheme(newTheme); }); // 更新主题切换图标 function updateThemeToggleIcon(theme) { const isDark = theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches); themeToggle.innerHTML = isDark ? `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun-icon lucide-sun"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>` : `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon-icon lucide-moon"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>`; } // 初始化主题切换图标 updateThemeToggleIcon(currentConfig.theme); document.getElementById('bingUploadBgBtn').addEventListener('click', function(e) { e.stopPropagation(); // 在手机上,使用accept属性限制文件类型 fileInput.accept = 'image/jpeg,image/png,image/webp'; fileInput.capture = 'environment'; // 允许直接拍照上传 fileInput.click(); }); fileInput.addEventListener('change', function(e) { if (this.files && this.files[0]) { const file = this.files[0]; // 可以保留一个初步的文件大小检查 if (file.size > 5 * 1024 * 1024) { // 比如原始文件不超过5MB alert('图片文件过大,请选择5MB以下的图片。脚本将尝试压缩。'); return; } const reader = new FileReader(); reader.onload = function(event) { const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); const MAX_WIDTH = 2560; // 最大宽度 const MAX_HEIGHT = 1440; // 最大高度 let width = img.width; let height = img.height; if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height); // 尝试使用 image/jpeg 或 image/webp 进行压缩 let compressedDataUrl = canvas.toDataURL('image/jpeg', 0.95); // 0.75 是压缩质量 console.log('Original size (approx Base64):', event.target.result.length); console.log('Compressed size:', compressedDataUrl.length); // 检查压缩后的大小是否仍然太大 (可选,但推荐) // data:URL 长度大约是字节数的 4/3 if (compressedDataUrl.length > 3.5 * 1024 * 1024 * 4/3) { // 估算压缩后localStorage占用约3.5MB alert('图片压缩后仍然过大,请尝试更小的图片或更高压缩率。'); // 可以尝试更低的质量或提示用户 // compressedDataUrl = canvas.toDataURL('image/jpeg', 0.6); // if (compressedDataUrl.length > ...) return; return; } try { document.cookie = 'SRCHD=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUID=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUSR=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; saveBackgroundImage(compressedDataUrl); // 保存压缩后的图片 applyConfig(getConfig()); showSaveSuccess('上传成功'); } catch (quotaError) { if (quotaError.name === 'QuotaExceededError') { alert('存储空间不足!即使压缩后图片仍然过大,请尝试更小的图片,或清理浏览器缓存后重试。'); // 考虑在这里提供清理旧背景的选项 // localStorage.removeItem(BG_IMAGE_KEY); } else { alert('发生未知错误: ' + quotaError.message); } } finally { closePanel(); // 确保面板关闭 } } img.onerror = function() { alert('无法加载图片文件。'); closePanel(); } img.src = event.target.result; // 先将原始 FileReader 結果给 Image 对象 } reader.onerror = function() { alert('读取文件失败。'); closePanel(); } reader.readAsDataURL(file); // 读取原始文件为 data URL this.value = ''; // 清空 file input } }); document.getElementById('bingResetBgBtn').addEventListener('click', function() { if (confirm('确定要重置背景图片吗?')) { saveBackgroundImage(''); applyConfig(getConfig()); document.cookie = 'SRCHD=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUID=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUSR=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; location.reload(); } }); document.getElementById('bingSaveConfigBtn').addEventListener('click', function() { const config = getConfig(); config.removehpTriviaOuter = document.getElementById('bingremovehpTriviaOuter').checked; config.removemusCard = document.getElementById('bingremovemusCard').checked; config.removeVsDefault = document.getElementById('bingremoveVsDefault').checked; config.removeFooter = document.getElementById('bingremoveFooter').checked; saveConfig(config); closePanel(); location.reload(); }); document.getElementById('bingExportConfigBtn').addEventListener('click', function() { const config = getConfig(); const configStr = JSON.stringify(config); const blob = new Blob([configStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'bing_background_config.json'; a.click(); URL.revokeObjectURL(url); }); document.getElementById('bingImportConfigBtn').addEventListener('click', function() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = e => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = event => { try { const config = JSON.parse(event.target.result); saveConfig(config); location.reload(); } catch (err) { alert('配置文件无效'); } }; reader.readAsText(file); }; input.click(); }); document.getElementById('bingResetConfigBtn').addEventListener('click', function() { if (confirm('确定要重置所有设置为默认值吗?')) { saveConfig(defaultConfig); saveBackgroundImage(''); document.cookie = 'SRCHD=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUID=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; document.cookie = 'SRCHUSR=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.bing.com'; location.reload(); } }); // 永久监听并移除不需要的元素 const observer = new MutationObserver(function() { const config = getConfig(); // 监听并移除切换按钮 if (config.removemusCard) { const musCard = document.querySelector('.musCard'); if (musCard) musCard.remove(); } // 监听并移除问答卡片 if (config.removehpTriviaOuter) { const hpTriviaOuter = document.querySelector('.hp_trivia_inner_new'); if (hpTriviaOuter) hpTriviaOuter.remove(); } // 监听并移除搜索框下方按钮 if (config.removeVsDefault) { const vsDefault = document.getElementById('vs_default'); if (vsDefault) vsDefault.remove(); } // 监听并移除页脚 if (config.removeFooter) { const footer = document.getElementById('footer'); if (footer) footer.remove(); } // 重载配置 applyConfig(currentConfig); }); observer.observe(document.body, { childList: true, subtree: true }); } // 启动脚本 init(); })();