您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
简约的goofish商品信息面板
// ==UserScript== // @name Goofish闲鱼商品图片自动下载器 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 简约的goofish商品信息面板 // @author 雷锋[email protected] // @match https://www.goofish.com/* // @match https://goofish.com/* // @match https://*.goofish.com/* // @include https://www.goofish.com/* // @include https://goofish.com/* // @include https://*.goofish.com/* // @grant GM_download // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant none // @license BSD-3-Clause // @run-at document-start // @noframes // ==/UserScript== (function() { 'use strict'; // 检查脚本环境 if (typeof GM_info !== 'undefined') { // Tampermonkey环境 } else { // 非Tampermonkey环境 } // 检查页面加载状态 function checkPageReady() { if (document.readyState === 'loading') { setTimeout(checkPageReady, 100); return; } } checkPageReady(); let itemData = null; let imageInfos = []; let panel = null; // 简化的下载设置 const downloadSettings = { format: 'jpg' // 固定使用JPG格式 }; // 创建迷你面板 function createMiniPanel() { if (panel) panel.remove(); panel = document.createElement('div'); panel.id = 'goofish-mini-panel'; panel.style.cssText = ` position: fixed; top: 20px; right: 20px; width: 340px; background: rgba(255, 255, 255, 0.98); border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); z-index: 10000; font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif; font-size: 14px; opacity: 0.15; transition: opacity 0.3s ease; cursor: move; backdrop-filter: blur(12px); overflow: hidden; will-change: transform; `; // 悬停显示 panel.addEventListener('mouseenter', () => panel.style.opacity = '1'); panel.addEventListener('mouseleave', () => panel.style.opacity = '0.15'); // 拖拽功能 - 高性能版本 let dragging = false; let startX, startY, startLeft, startTop; panel.addEventListener('mousedown', (e) => { // 只允许在标题栏拖拽,排除关闭按钮 if (e.target.closest('[data-drag-handle]') && !e.target.closest('button[onclick*="closest"]')) { dragging = true; startX = e.clientX; startY = e.clientY; startLeft = panel.offsetLeft; startTop = panel.offsetTop; panel.style.cursor = 'grabbing'; // 拖拽时禁用所有可能影响性能的CSS效果 panel.style.transition = 'none'; panel.style.backdropFilter = 'none'; panel.style.boxShadow = '0 4px 16px rgba(0, 0, 0, 0.2)'; // 简化阴影 e.preventDefault(); } }); document.addEventListener('mousemove', (e) => { if (dragging) { e.preventDefault(); // 直接设置位置,不使用requestAnimationFrame避免延迟 const newLeft = startLeft + e.clientX - startX; const newTop = startTop + e.clientY - startY; panel.style.left = newLeft + 'px'; panel.style.top = newTop + 'px'; panel.style.right = 'auto'; } }); document.addEventListener('mouseup', () => { if (dragging) { dragging = false; panel.style.cursor = 'move'; // 恢复所有CSS效果 panel.style.transition = 'opacity 0.3s ease'; panel.style.backdropFilter = 'blur(12px)'; panel.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08)'; } }); updatePanel(); document.body.appendChild(panel); } // 更新面板内容 function updatePanel() { if (!panel) return; if (!itemData || !imageInfos.length) { panel.innerHTML = ` <div style="padding: 10px; background: #007bff; color: white; border-radius: 8px 8px 0 0; text-align: center; font-weight: bold;"> 🛍️ Goofish商品信息 </div> <div style="padding: 20px; text-align: center; color: #666;"> 等待获取商品数据... </div> `; return; } const title = itemData.title || '未知商品'; const price = itemData.soldPrice || '未知'; const desc = itemData.desc || '暂无描述'; // 修复图片URL(解决Mixed Content问题) function fixImageUrl(url) { if (!url) return ''; // 如果是相对路径,添加HTTPS协议 if (url.startsWith('//')) { return 'https:' + url; } // 如果是http,强制改为https(解决Mixed Content问题) if (url.startsWith('http://')) { const httpsUrl = url.replace('http://', 'https://'); return httpsUrl; } return url; } // 九宫格图片 const imageGrid = imageInfos.slice(0, 9).map((img, index) => { const fixedUrl = fixImageUrl(img.url); return ` <div style=" aspect-ratio: 1; background: #f0f0f0; border-radius: 4px; overflow: hidden; cursor: pointer; position: relative; transition: transform 0.2s ease; " onmouseover="this.style.transform='scale(1.1)'" onmouseout="this.style.transform='scale(1)'" onclick="downloadImage('${img.url}', '${index + 1}')" title="点击下载"> <img src="${fixedUrl}" style="width: 100%; height: 100%; object-fit: cover;" onerror="this.style.display='none'; this.parentElement.innerHTML='<div style=\\'display: flex; align-items: center; justify-content: center; height: 100%; background: #f0f0f0; color: #999; font-size: 10px;\\'>图片加载失败</div>'" onload="" loading="lazy"> <div style=" position: absolute; bottom: 1px; right: 1px; background: rgba(0,0,0,0.7); color: white; padding: 1px 3px; border-radius: 2px; font-size: 8px; ">${index + 1}</div> <div style=" position: absolute; top: 2px; right: 2px; background: rgba(220,53,69,0.8); color: white; width: 16px; height: 16px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; cursor: pointer; opacity: 0; transition: opacity 0.2s ease; " onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0'" onclick="event.stopPropagation(); removeImage(${index})" title="删除图片">×</div> </div> `; }).join(''); panel.innerHTML = ` <!-- Win11风格标题栏 --> <div data-drag-handle="true" style=" display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; background: linear-gradient(135deg, #ffe60f, #ffe60f); color: white; border-radius: 8px 8px 0 0; font-weight: 600; font-size: 14px; user-select: none; cursor: move; "> <div style="display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;"> <span style="font-size: 16px;">🛍️</span> <span style="color: #000; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="${title}"> ${title} </span> </div> <div style="display: flex; align-items: center; gap: 4px;"> <button onclick="this.closest('#goofish-mini-panel').style.display='none'" style=" width: 20px; height: 20px; background: rgba(255,255,255,0.2); border: none; border-radius: 4px; color: #000; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 12px; transition: background 0.2s ease; " onmouseover="this.style.background='rgba(255,255,255,0.3)'" onmouseout="this.style.background='rgba(255,255,255,0.2)'" title="关闭"> ✕ </button> </div> </div> <div style="padding: 16px;"> <!-- 商品信息 --> <div style="margin-bottom: 16px; padding: 12px; background: #f8f9fa; border-radius: 8px; border: 1px solid rgba(0, 0, 0, 0.05);"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;"> <span style="font-weight: 700; color: #e74c3c; font-size: 20px;">¥${price}</span> <span style="color: #6c757d; font-size: 13px; font-weight: 500;">${imageInfos.length}张</span> </div> <div style="color: #495057; font-size: 13px; line-height: 1.5; max-height: 65px; overflow-y: auto;"> ${desc.substring(0, 120)}${desc.length > 120 ? '...' : ''} </div> </div> <!-- 九宫格 --> <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-bottom: 16px;"> ${imageGrid} </div> <!-- 按钮 --> <div style="display: flex; gap: 10px; margin-bottom: 16px;"> <button onclick="downloadAll()" style=" flex: 1; padding: 12px 16px; background: linear-gradient(135deg, #ffe60f, #ffe60f); color: #000; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 600; transition: all 0.2s ease; box-shadow: 0 2px 8px rgba(40, 167, 69, 0.3); " onmouseover="this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 12px rgba(40, 167, 69, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 8px rgba(40, 167, 69, 0.3)'"> 📥 全部下载 </button> <button onclick="copyUrls()" style=" flex: 1; padding: 12px 16px; background: linear-gradient(135deg, #3b3b3b, #3b3b3b); color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 600; transition: all 0.2s ease; box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3); " onmouseover="this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 12px rgba(108, 117, 125, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 8px rgba(108, 117, 125, 0.3)'"> 📋 复制链接 </button> </div> <!-- 下载状态 --> <div id="downloadStatus" style=" display: none; margin-bottom: 12px; padding: 10px; background: linear-gradient(135deg, #d4edda, #c3e6cb); border: 1px solid #b8dacc; border-radius: 8px; font-size: 13px; color: #155724; text-align: center; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); "> <span id="downloadProgress">准备下载...</span> </div> </div> `; } // 下载功能 - Tampermonkey兼容版本 window.downloadImage = async function(url, filename) { // 修复Mixed Content问题 if (url.startsWith('http://')) { url = url.replace('http://', 'https://'); } try { // 方法1:尝试使用GM_xmlhttpRequest(Tampermonkey专用) if (typeof GM_xmlhttpRequest !== 'undefined') { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, responseType: 'blob', onload: function(response) { try { const blob = response.response; const blobUrl = URL.createObjectURL(blob); const aTag = document.createElement('a'); aTag.href = blobUrl; aTag.download = filename.replace(/[<>:"/\\|?*]/g, '_') + '.' + downloadSettings.format; document.body.appendChild(aTag); aTag.click(); document.body.removeChild(aTag); URL.revokeObjectURL(blobUrl); resolve(); } catch (error) { reject(error); } }, onerror: function(error) { reject(error); } }); }); } // 方法2:使用fetch API(可能被CORS阻止) const response = await fetch(url, { mode: 'cors', credentials: 'omit' }); if (!response.ok) { throw new Error(`请求失败: ${response.status}`); } const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); const aTag = document.createElement('a'); aTag.href = blobUrl; aTag.download = filename.replace(/[<>:"/\\|?*]/g, '_') + '.' + downloadSettings.format; document.body.appendChild(aTag); aTag.click(); document.body.removeChild(aTag); URL.revokeObjectURL(blobUrl); } catch (error) { // 方法3:最后的备用方案 - 直接链接下载 try { const aTag = document.createElement('a'); aTag.href = url; aTag.download = filename.replace(/[<>:"/\\|?*]/g, '_') + '.' + downloadSettings.format; aTag.target = '_blank'; document.body.appendChild(aTag); aTag.click(); document.body.removeChild(aTag); } catch (fallbackError) { throw error; } } }; // 高级图片下载功能 - Tampermonkey兼容版本 window.downloadImageAdvanced = async function(url, filename) { // 修复Mixed Content问题 if (url.startsWith('http://')) { url = url.replace('http://', 'https://'); } // 检查是否需要格式转换 const needsConversion = url.includes('.heic') || (url.includes('.webp') && downloadSettings.format === 'jpg') || (url.includes('.png') && downloadSettings.format === 'jpg'); if (needsConversion) { try { let blob; // 使用GM_xmlhttpRequest获取图片(Tampermonkey专用) if (typeof GM_xmlhttpRequest !== 'undefined') { blob = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, responseType: 'blob', onload: function(response) { resolve(response.response); }, onerror: function(error) { reject(error); } }); }); } else { // 使用fetch API const response = await fetch(url, { mode: 'cors', credentials: 'omit' }); if (!response.ok) { throw new Error(`请求失败: ${response.status}`); } blob = await response.blob(); } // 创建图片元素进行格式转换 const img = new Image(); img.crossOrigin = 'anonymous'; return new Promise((resolve, reject) => { img.onload = function() { try { // 创建Canvas进行格式转换 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; // 绘制图片到Canvas ctx.drawImage(img, 0, 0); // 根据设置选择输出格式 const mimeType = downloadSettings.format === 'jpg' ? 'image/jpeg' : downloadSettings.format === 'png' ? 'image/png' : 'image/webp'; const quality = downloadSettings.format === 'jpg' ? 0.9 : 1.0; canvas.toBlob(function(convertedBlob) { if (convertedBlob) { try { // 使用转换后的blob下载 const downloadUrl = URL.createObjectURL(convertedBlob); const aTag = document.createElement('a'); aTag.href = downloadUrl; aTag.download = filename.replace(/[<>:"/\\|?*]/g, '_') + '.' + downloadSettings.format; document.body.appendChild(aTag); aTag.click(); document.body.removeChild(aTag); URL.revokeObjectURL(downloadUrl); resolve(); } catch (error) { reject(error); } } else { downloadImage(url, filename).then(resolve).catch(reject); } }, mimeType, quality); } catch (error) { downloadImage(url, filename).then(resolve).catch(reject); } }; img.onerror = function() { downloadImage(url, filename).then(resolve).catch(reject); }; img.src = URL.createObjectURL(blob); }); } catch (error) { await downloadImage(url, filename); } } else { // 直接下载 await downloadImage(url, filename); } }; window.downloadAll = async function() { if (!imageInfos || imageInfos.length === 0) { alert('❌ 没有可下载的图片!'); return; } const total = imageInfos.length; let completed = 0; // 显示下载进度 const showProgress = () => { // 更新面板中的进度显示 const statusDiv = document.getElementById('downloadStatus'); const progressSpan = document.getElementById('downloadProgress'); if (statusDiv && progressSpan) { statusDiv.style.display = 'block'; progressSpan.textContent = `下载进度: ${completed}/${total}`; if (completed === total) { statusDiv.style.background = '#d1ecf1'; statusDiv.style.borderColor = '#bee5eb'; statusDiv.style.color = '#0c5460'; progressSpan.textContent = `✅ 下载完成!共 ${total} 张图片`; // 3秒后隐藏状态 setTimeout(() => { statusDiv.style.display = 'none'; }, 3000); } } }; // 显示初始状态 showProgress(); // 顺序下载图片(完全使用1.html方案) for (let i = 0; i < imageInfos.length; i++) { try { const img = imageInfos[i]; const filename = `${i + 1}`; // 使用数字序号 // 使用1.html的下载方案 await downloadImage(img.url, filename); completed++; showProgress(); // 延迟避免浏览器限制 if (i < imageInfos.length - 1) { await new Promise(resolve => setTimeout(resolve, 500)); } } catch (error) { completed++; showProgress(); } } }; window.copyUrls = function() { const urls = imageInfos.map(img => img.url).join('\n'); navigator.clipboard.writeText(urls).then(() => { alert('图片链接已复制!'); }).catch(() => { const textArea = document.createElement('textarea'); textArea.value = urls; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); alert('图片链接已复制!'); }); }; // 删除图片功能 window.removeImage = function(index) { if (imageInfos && imageInfos.length > index) { imageInfos.splice(index, 1)[0]; // 更新面板显示 updatePanel(); } }; // 拦截请求 - 简化版(参考test.js) const originalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; xhr.open = function(method, url, async, user, password) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; xhr.send = function(data) { this.addEventListener('readystatechange', function() { if (this.readyState === 4 && this.status === 200 && this._url.includes('/h5/mtop.taobao.idle.pc.detai')) { try { const jsonData = JSON.parse(this.responseText); if (jsonData?.data?.itemDO?.imageInfos) { itemData = jsonData.data.itemDO; imageInfos = itemData.imageInfos; if (!panel) createMiniPanel(); updatePanel(); } } catch (e) { // 解析失败,静默处理 } } }); return originalSend.apply(this, arguments); }; return xhr; }; // 自动创建面板(不依赖测试按钮) function autoCreatePanel() { if (document.body && !panel) { createMiniPanel(); // 如果5秒后还没有数据,使用测试数据 setTimeout(() => { if (!itemData || !imageInfos.length) { itemData = { title: '等待获取商品数据...', soldPrice: '--', desc: '正在拦截API请求,请稍候...' }; imageInfos = []; updatePanel(); } }, 5000); } } // 页面加载完成后自动创建面板 setTimeout(autoCreatePanel, 1000); // Mixed Content检测和修复功能(内部使用) function fixMixedContent(url) { if (!url) return url; // 检测Mixed Content问题 const isHttpsPage = window.location.protocol === 'https:'; const isHttpUrl = url.startsWith('http://'); if (isHttpsPage && isHttpUrl) { const httpsUrl = url.replace('http://', 'https://'); return httpsUrl; } return url; } // 专业的开发者信息和功能说明 console.log('%c🛍️ Goofish闲鱼商品图片自动下载器 v1.1', 'color: #0078d4; font-size: 16px; font-weight: bold;'); console.log('%c━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'color: #0078d4;'); console.log('%c📋 功能说明:', 'color: #28a745; font-weight: bold;'); console.log(' • 自动拦截Goofish闲鱼商品API数据'); console.log(' • 显示商品信息(标题、价格、描述)'); console.log(' • 九宫格图片预览和下载'); console.log(' • 支持单张/批量下载(数字序号命名)'); console.log(' • 图片删除功能'); console.log(' • Win11风格拖拽面板'); console.log(' • 自动修复Mixed Content问题'); console.log(' • 作者Email:雷锋[email protected]'); console.log('%c━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'color: #0078d4;'); console.log('%c✅ 脚本已启动,等待拦截商品数据...', 'color: #28a745; font-weight: bold;'); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址