京东商详主图 评论 以及买家秀同步功能更新
发表于 ・ 视频
1:下载豆包插件,设置豆包 增加功能以及置顶功能
2:加载插件代码。

// ==UserScript==
// @name 京东商详页面下载
// @namespace http://tampermonkey.net/
// @version 4.1
// @description 主图/媒体图单选切换,3:4预览,排除功能,粘贴自动识别SKU/标题/描述
// @author You
// @include *://item.jd.*/*
// @grant GM_registerMenuCommand
// @require https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
// ==/UserScript==
(function() {
'use strict';
const CONFIG = { waitParseTime: 1500, autoRun: true, defaultMode: 'main' };
let globalProductInfo = {};
let globalMainImageList = [];
let globalMediaImageList = [];
let currentMode = CONFIG.defaultMode;
let panelDom = null;
let globalExcludedMediaUrls = new Set();
let globalRootDirHandle = null;
let globalFromClipboard = false;
let globalOriginalInfo = null;
let globalEmbeddedInfo = null;
let clipboardTimer = null;
let lastClipboard = '';
let clipboardWatching = false;
function generateRandomSuffix() {
const len = Math.floor(Math.random() * 4) + 3;
const c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let r = '';
for (let i = 0; i < len; i++) r += c[Math.floor(Math.random() * c.length)];
return r;
}
function setStatus(msg, persistent) {
const el = document.getElementById('jd-status');
if (!el) return;
el.textContent = msg;
el.style.opacity = '1';
if (!persistent) {
clearTimeout(el._timer);
el._timer = setTimeout(() => { el.style.opacity = '0'; }, 3000);
}
}
function setStatusRed(msg) {
const el = document.getElementById('jd-status');
if (!el) return;
el.textContent = msg;
el.style.opacity = '1';
el.style.color = '#e4393c';
}
function updateParseInfo(parsed) {
globalEmbeddedInfo = { sku: parsed.sku, title: parsed.title, description: parsed.description };
const info = document.getElementById('jd-parse-info');
if (!info) return;
const orig = globalOriginalInfo || parsed;
info.textContent = `原来:SKU ${orig.sku} ${orig.title.slice(0,20)} → 嵌入:SKU ${parsed.sku} ${parsed.title.slice(0,20)} ✅`;
}
function clearEmbedded() {
globalEmbeddedInfo = null;
globalFromClipboard = false;
const info = document.getElementById('jd-parse-info');
if (info) info.textContent = '';
}
// ───── 剪贴板轮询监控 ─────
function stopClipWatch() {
if (clipboardTimer) { clearInterval(clipboardTimer); clipboardTimer = null; }
clipboardWatching = false;
}
async function startClipWatch() {
stopClipWatch();
try {
// 用户点击按钮后触发 -> 浏览器弹出剪贴板权限提示
const t = await navigator.clipboard.readText();
lastClipboard = t || '';
} catch (_) {
setStatusRed('⚠️ 剪贴板授权失败,请重试');
return;
}
clipboardWatching = true;
setStatusRed('📋 剪贴板监控中');
clipboardTimer = setInterval(async () => {
try {
const t = await navigator.clipboard.readText();
if (t && t !== lastClipboard) {
console.log('[剪贴板] 内容变化:', t.slice(0, 60));
lastClipboard = t;
const parsed = parseProductText(t);
if (parsed) {
globalFromClipboard = true;
updateParseInfo(parsed);
setStatusRed(`✅ 嵌入 SKU ${parsed.sku}`);
}
}
} catch (_) { /* polling继续 */ }
}, 1500);
}
function dbOpen() {
return new Promise((res, rej) => {
const r = indexedDB.open('jd-store', 1);
r.onupgradeneeded = () => r.result.createObjectStore('kv');
r.onsuccess = () => res(r.result);
r.onerror = () => rej(r.error);
});
}
async function saveRootHandle(h) {
try {
const db = await dbOpen();
await new Promise((res, rej) => {
const tx = db.transaction('kv', 'readwrite');
tx.objectStore('kv').put(h, 'rootDir');
tx.oncomplete = res;
tx.onerror = () => rej(tx.error);
});
} catch (e) { console.warn('保存目录失败:', e); }
}
async function loadRootHandle() {
try {
const db = await dbOpen();
return await new Promise((res, rej) => {
const tx = db.transaction('kv', 'readonly');
const g = tx.objectStore('kv').get('rootDir');
g.onsuccess = () => res(g.result);
g.onerror = () => rej(g.error);
});
} catch (e) { return null; }
}
async function getDirHandle() {
if (globalRootDirHandle) {
const p = await globalRootDirHandle.queryPermission({ mode: 'readwrite' });
if (p === 'granted') return globalRootDirHandle;
}
const stored = await loadRootHandle();
if (stored) {
let p = await stored.queryPermission({ mode: 'readwrite' });
if (p !== 'granted') p = await stored.requestPermission({ mode: 'readwrite' });
if (p === 'granted') { globalRootDirHandle = stored; return stored; }
}
const h = await window.showDirectoryPicker({ mode: 'readwrite', startIn: 'downloads' });
globalRootDirHandle = h;
saveRootHandle(h);
return h;
}
function parseProductText(text) {
console.log('[解析] 原始:', JSON.stringify(text.slice(0, 100)));
const clean = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
.replace(/[\u200B-\u200D\uFEFF\u00AD]/g, '').trim();
// 用 ====== (6个以上等号) 分隔,不要求换行
const parts = clean.split(/={6,}/).map(s => s.trim());
console.log('[解析] 分段数:', parts.length);
if (parts.length < 3) { console.log('[解析] 段数不足3'); return null; }
const digits = parts[0].replace(/\D/g, '');
if (digits.length < 6) { console.log('[解析] SKU数字不足'); return null; }
const title = parts[1].replace(/[\\/:*?"<>|\r\n]/g, '').replace(/\s+/g, ' ').trim();
if (!title) { console.log('[解析] 标题为空'); return null; }
const description = parts.slice(2).join('\n').trim();
console.log('[解析] 成功 SKU:', digits, '标题:', title);
return { sku: digits, title, description };
}
function handlePastedText(text) {
console.log('[粘贴] 收到文本:', text.slice(0, 80));
const parsed = parseProductText(text);
if (!parsed) {
setStatusRed('⚠️ 格式不符:需用 ====== 分隔 SKU / 标题 / 描述');
return;
}
globalFromClipboard = true;
updateParseInfo(parsed);
setStatusRed(`✅ 嵌入 SKU ${parsed.sku}`);
}
// ───── 1. 商品信息提取 ─────
function extractProductInfo() {
let sku = null, productTitle = '未知商品';
const fullHtml = document.documentElement.innerHTML;
const cr = /<a[^>]+href="([^"]*chat\.jd\.com[^"]*)"[^>]*>/g;
let m;
while ((m = cr.exec(fullHtml)) !== null) {
const p = m[1].match(/[?&]pid=(\d+)/);
if (p && p[1]) { sku = p[1]; console.log('SKU(pid):', sku); break; }
}
if (!sku) {
const u = window.location.pathname.match(/\/(\d+)\.html/);
sku = u ? u[1] : 'unknown_sku';
}
const t1 = document.querySelector('.sku-title-name');
const t2 = document.querySelector('.sku-name');
if (t1) productTitle = t1.innerText.trim();
else if (t2) productTitle = t2.innerText.trim();
else productTitle = document.title.replace(/【.*?】|京东|,.*/g, '').trim();
const safe = productTitle.replace(/[\\/:*?"<>|\r\n]/g, '').replace(/\s+/g, ' ');
globalFromClipboard = false;
globalEmbeddedInfo = null;
globalOriginalInfo = { sku, title: safe };
globalProductInfo = { sku, title: safe, folderName: `${sku}----${safe}`, description: '' };
return globalProductInfo;
}
// ───── 2. 主图提取 ─────
function extractMainImages() {
const set = new Set();
const cc = document.querySelector('.image-carousel-content');
if (cc) {
cc.querySelectorAll('img').forEach(img => {
let s = img.src || img.getAttribute('data-lazy-img') || img.getAttribute('src');
if (s) {
if (s.startsWith('//')) s = 'https:' + s;
set.add(s.replace(/\/s\d+x\d+_/, '/').replace('.avif', ''));
}
});
} else {
const re = /(https?:)?\/\/img\d+\.360buyimg\.com\/[^"'\s]+\.(avif|jpg|png)/g;
let m;
while ((m = re.exec(fullHtml)) !== null) {
let u = m[0].startsWith('//') ? 'https:' + m[0] : m[0];
set.add(u.replace(/\/s\d+x\d+_/, '/').replace('.avif', ''));
}
}
globalMainImageList = Array.from(set);
return globalMainImageList;
}
// ───── 3. 媒体图提取 ─────
function extractMediaImages() {
const set = new Set();
const mc = document.querySelector('.jdc-pc-media-preview-list');
if (!mc) { setStatusRed('⚠️ 未找到媒体层容器'); return []; }
mc.querySelectorAll('img').forEach(img => {
let s = img.src || img.getAttribute('data-lazy-img') || img.getAttribute('data-src')
|| img.getAttribute('origin-src') || img.getAttribute('src');
if (s) {
if (s.startsWith('//')) s = 'https:' + s;
set.add(s.replace(/\/s\d+x\d+_/, '/').replace('.avif', ''));
}
});
globalExcludedMediaUrls = new Set();
globalMediaImageList = Array.from(set);
renderInfoPanel();
if (globalMediaImageList.length > 0) setStatusRed(`✅ 已提取 ${globalMediaImageList.length} 张`);
return globalMediaImageList;
}
function switchMode(t) {
if (t === currentMode) return;
currentMode = t;
renderInfoPanel();
}
// ───── 4. 面板渲染 ─────
function renderInfoPanel() {
if (panelDom) document.body.removeChild(panelDom);
panelDom = document.createElement('div');
panelDom.id = 'jd-extract-panel';
const ss = document.createElement('style');
ss.textContent = `
#jd-extract-panel { --jd-red:#e4393c; --jd-orange:#ff6a00; --jd-blue:#1a73e8; --jd-green:#34a853; }
#jd-extract-panel .jb { transition:all .2s; cursor:pointer; user-select:none; }
#jd-extract-panel .jb:hover { filter:brightness(1.08); transform:translateY(-1px); }
#jd-extract-panel .jb:active { transform:translateY(0); filter:brightness(.95); }
#jd-extract-panel .jb:disabled { opacity:.4; cursor:not-allowed; filter:none; transform:none; }
#jd-extract-panel .jc { transition:all .25s; }
#jd-extract-panel .jc:hover { transform:translateY(-3px); box-shadow:0 6px 16px rgba(0,0,0,.1); }
#jd-extract-panel .jc-ex { opacity:.5; }
#jd-extract-panel ::-webkit-scrollbar { height:5px; }
#jd-extract-panel ::-webkit-scrollbar-track { background:transparent; }
#jd-extract-panel ::-webkit-scrollbar-thumb { background:#ddd; border-radius:3px; }
#jd-extract-panel #jd-paste-area:focus { outline:none; border-color:var(--jd-red); }
`;
panelDom.appendChild(ss);
const w = document.createElement('div');
w.style.cssText = `position:fixed;bottom:0;left:0;right:0;z-index:99999999;background:#fff;box-shadow:0 -6px 30px rgba(0,0,0,.06);border-radius:16px 16px 0 0;max-height:52vh;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Microsoft YaHei",sans-serif;font-size:13px;color:#1a1a1a;border-top:3px solid var(--jd-red);`;
const { sku, title } = globalProductInfo;
const main = currentMode === 'main';
const list = main ? globalMainImageList : globalMediaImageList;
const cnt = list.length;
w.innerHTML = `
<div style="display:flex;align-items:center;gap:6px;padding:7px 14px;border-bottom:1px solid #f0f0f0;flex-shrink:0;background:linear-gradient(180deg,#fefefe,#f8f8f8);">
<span style="background:var(--jd-red);color:#fff;font-size:10px;font-weight:700;padding:2px 8px 2px 6px;border-radius:4px;white-space:nowrap;">⬦ 京东</span>
<span style="background:#fff0f0;color:var(--jd-red);font-size:10px;font-weight:600;padding:1px 6px;border-radius:3px;white-space:nowrap;">${sku}</span>
<span style="color:#888;font-size:11px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;">${title}</span>
<span style="font-size:11px;font-weight:600;color:${main?'var(--jd-red)':'var(--jd-orange)'};background:${main?'#fff0f0':'#fff3e0'};padding:1px 8px;border-radius:20px;white-space:nowrap;">${cnt}张</span>
<div style="display:flex;gap:1px;background:#ebebeb;border-radius:5px;padding:2px;">
<button id="mmb" class="jb" style="border:none;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;${main?'background:var(--jd-red);color:#fff':'background:transparent;color:#888'};">主图</button>
<button id="mmd" class="jb" style="border:none;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;${!main?'background:var(--jd-orange);color:#fff':'background:transparent;color:#888'};">媒体</button>
</div>
${main ? `
<button id="dlb" class="jb" style="border:none;background:var(--jd-red);color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;">⬇ 下载</button>
<button id="refb" class="jb" style="border:none;background:var(--jd-blue);color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;">↻ 刷新</button>
` : `
<button id="extb" class="jb" style="border:none;background:var(--jd-orange);color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;">⟐ 提取</button>
<button id="dlb" class="jb" style="border:none;background:#e67e22;color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;" ${cnt===0?'disabled':''}>⬇ 下载</button>
`}
<button id="cpyb" class="jb" style="border:none;background:var(--jd-green);color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;">📋 复制</button>
<button id="clipb" class="jb" style="border:none;background:#9e9e9e;color:#fff;border-radius:4px;padding:3px 10px;font-size:10px;font-weight:600;white-space:nowrap;">📋 监控</button>
<span id="jd-status" style="font-size:10px;font-weight:600;white-space:nowrap;transition:opacity .5s;opacity:0;flex-shrink:0;color:#e4393c;"></span>
<button id="closeb" class="jb" style="border:none;background:transparent;padding:2px 4px;font-size:14px;color:#bbb;line-height:1;">✕</button>
</div>
<div style="display:flex;gap:6px;padding:4px 14px;flex-shrink:0;align-items:center;border-bottom:1px solid #f5f5f5;">
<span style="font-size:10px;color:#999;white-space:nowrap;">📝 粘贴识别</span>
<input id="jd-paste-area" type="text" placeholder="粘贴商品描述(首行SKU/次行标题/余下描述)" style="flex:1;font-size:10px;padding:3px 8px;border:1px solid #e0e0e0;border-radius:4px;color:#333;background:#fafafa;min-width:0;">
<span id="jd-parse-info" style="font-size:10px;color:var(--jd-red);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:280px;"></span>
</div>
<div style="flex:1;overflow-x:auto;overflow-y:hidden;padding:6px 14px 8px;display:flex;gap:6px;align-items:stretch;">
${cnt===0
? `<div style="display:flex;align-items:center;justify-content:center;width:100%;color:#ccc;font-size:12px;">${main?'暂无主图':'暂无媒体图,请点击【提取】'}</div>`
: list.map((url,i) => {
const ex = !main && globalExcludedMediaUrls.has(url);
return `<div class="jc ${ex?'jc-ex':''}" style="flex:0 0 auto;width:85px;position:relative;border:1px solid ${ex?'var(--jd-red)':'#e8e8e8'};border-radius:8px;overflow:hidden;background:${ex?'#fafafa':'#fff'};display:flex;flex-direction:column;">
${!main ? `<button class="exb" data-url="${url}" style="position:absolute;top:2px;right:2px;z-index:10;width:18px;height:18px;border:none;border-radius:50%;background:${ex?'var(--jd-red)':'rgba(0,0,0,.25)'};color:#fff;font-size:10px;line-height:18px;text-align:center;cursor:pointer;padding:0;font-weight:700;">${ex?'↺':'×'}</button>` : ''}
<div style="position:relative;">
<div style="position:absolute;top:2px;left:2px;z-index:5;background:rgba(0,0,0,.45);color:#fff;font-size:8px;font-weight:600;padding:0 5px;border-radius:3px;line-height:1.6;">${i}</div>
<a href="${url}" target="_blank" style="display:block;text-decoration:none;">
<img src="${url}" style="width:85px;height:113px;object-fit:cover;display:block;${ex?'opacity:.35':''}" alt="" onerror="this.parentElement.innerHTML='<div style=\\'width:85px;height:113px;display:flex;align-items:center;justify-content:center;background:#f5f5f5;color:#ccc;font-size:9px;\\'>×</div>'">
</a>
</div>
<div style="padding:1px 4px;text-align:center;font-size:9px;color:${ex?'var(--jd-red)':'#aaa'};line-height:1.5;background:${ex?'#fff5f5':'#fafafa'};">${main?'P':'M'}${i}${ex?' ✕':''}</div>
</div>`;
}).join('')
}
</div>
`;
panelDom.appendChild(w);
document.body.appendChild(panelDom);
bindEvents();
}
// ───── 5. 事件绑定 ─────
function bindEvents() {
const $ = id => document.getElementById(id);
$('closeb').addEventListener('click', () => { stopClipWatch(); if (panelDom) document.body.removeChild(panelDom); panelDom = null; });
$('mmb').addEventListener('click', () => switchMode('main'));
$('mmd').addEventListener('click', () => switchMode('media'));
$('cpyb').addEventListener('click', async () => {
const { sku, title } = globalProductInfo;
try {
await navigator.clipboard.writeText(`${sku}----${title}`);
const b = $('cpyb');
const ot = b.innerText;
b.innerText = '✅ 已复制'; b.style.background = '#218838';
setTimeout(() => { b.innerText = ot; b.style.background = '#34a853'; }, 1500);
} catch (e) { setStatusRed('❌ 复制失败'); }
});
// 剪贴板监控开关
const clipBtn = $('clipb');
if (clipBtn) {
clipBtn.addEventListener('click', async () => {
if (clipboardWatching) {
stopClipWatch();
clipBtn.innerText = '📋 监控';
clipBtn.style.background = '#9e9e9e';
setStatusRed('⏹ 监控已停止');
} else {
clipBtn.innerText = '⏳ 授权中...';
clipBtn.disabled = true;
await startClipWatch();
clipBtn.disabled = false;
if (clipboardWatching) {
clipBtn.innerText = '📋 监控中';
clipBtn.style.background = '#e4393c';
} else {
clipBtn.innerText = '📋 监控';
clipBtn.style.background = '#9e9e9e';
}
}
});
}
if (currentMode === 'main') {
$('refb').addEventListener('click', () => { extractMainImages(); renderInfoPanel(); setStatusRed(`✅ ${globalMainImageList.length}张`); });
$('dlb').addEventListener('click', downloadMain);
} else {
$('extb').addEventListener('click', extractMediaImages);
$('dlb').addEventListener('click', downloadMedia);
document.querySelectorAll('.exb').forEach(b => {
b.addEventListener('click', function(e) {
e.preventDefault(); e.stopPropagation();
const u = this.dataset.url;
globalExcludedMediaUrls.has(u) ? globalExcludedMediaUrls.delete(u) : globalExcludedMediaUrls.add(u);
renderInfoPanel();
});
});
}
// 全局粘贴监听(页面任意位置 Ctrl+V 自动识别)
document.addEventListener('paste', e => {
// 如果粘贴目标是我们自己的输入框,跳过(由输入框处理器处理)
if (e.target && e.target.id === 'jd-paste-area') return;
const text = (e.clipboardData || window.clipboardData).getData('text');
if (text && text.trim()) {
const test = parseProductText(text.trim());
if (test) {
e.preventDefault();
handlePastedText(text.trim());
}
}
});
// 输入框粘贴/输入识别
const pa = $('jd-paste-area');
if (pa) {
pa.addEventListener('paste', () => {
setTimeout(() => {
const v = pa.value.trim();
if (v) { handlePastedText(v); pa.value = ''; }
}, 50);
});
pa.addEventListener('blur', () => {
const v = pa.value.trim();
if (v) { handlePastedText(v); pa.value = ''; }
});
}
}
// ───── 6. 下载(主图 → index/) ─────
async function downloadMain() {
const embed = globalEmbeddedInfo;
const useSku = embed ? embed.sku : globalProductInfo.sku;
const useTitle = embed ? embed.title : globalProductInfo.title;
const useDesc = embed ? (embed.description || useTitle) : globalProductInfo.title;
const urls = globalMainImageList;
const sfx = globalFromClipboard ? '' : generateRandomSuffix();
const folder = `${useSku}----${useTitle}${sfx}`;
if (!urls.length) { setStatusRed('⚠️ 无主图'); return; }
if (!window.showDirectoryPicker) { setStatusRed('⚠️ 需 Chrome 86+'); return; }
const btn = document.getElementById('dlb');
if (!btn) return;
const ot = btn.innerText;
btn.innerText = '⏳...'; btn.disabled = true;
try {
const root = await getDirHandle();
const idx = await root.getDirectoryHandle('index', { create: true });
const pd = await idx.getDirectoryHandle(folder, { create: true });
const tf = await pd.getFileHandle('skutitle.txt', { create: true });
const tw = await tf.createWritable();
await tw.write(useDesc);
await tw.close();
let ok = 0;
for (let i = 0; i < urls.length; i++) {
try {
btn.innerText = `${i+1}/${urls.length}`;
const r = await axios.get(urls[i], { responseType: 'blob', timeout: 15000 });
const ext = urls[i].includes('.png') ? 'png' : urls[i].includes('.webp') ? 'webp' : 'jpg';
const f = await pd.getFileHandle(`${i}.${ext}`, { create: true });
const w = await f.createWritable();
await w.write(r.data);
await w.close();
ok++;
} catch (e) { console.error('主图失败', i, e); }
}
btn.innerText = ot; btn.disabled = false;
clearEmbedded();
setStatusRed(`✅ ${ok}/${urls.length}`);
} catch (e) {
console.error('[下载]', e);
btn.innerText = ot; btn.disabled = false;
if (e.name !== 'AbortError') setStatusRed('❌ 下载出错');
}
}
// ───── 7. 下载(媒体图 → contents/) ─────
async function downloadMedia() {
const embed = globalEmbeddedInfo;
const useSku = embed ? embed.sku : globalProductInfo.sku;
const useTitle = embed ? embed.title : globalProductInfo.title;
const useDesc = embed ? (embed.description || useTitle) : globalProductInfo.title;
const sfx = globalFromClipboard ? '' : generateRandomSuffix();
const folder = `${useSku}----${useTitle}${sfx}`;
const urls = globalMediaImageList.filter(u => !globalExcludedMediaUrls.has(u));
if (!urls.length) { setStatusRed(globalExcludedMediaUrls.size ? '⚠️ 已全部排除' : '⚠️ 无媒体图'); return; }
if (!window.showDirectoryPicker) { setStatusRed('⚠️ 需 Chrome 86+'); return; }
const btn = document.getElementById('dlb');
if (!btn) return;
const ot = btn.innerText;
btn.innerText = '⏳...'; btn.disabled = true;
try {
const root = await getDirHandle();
const ct = await root.getDirectoryHandle('contents', { create: true });
const pd = await ct.getDirectoryHandle(folder, { create: true });
try { await pd.getFileHandle('skutitle.txt', { create: false }); }
catch {
const f = await pd.getFileHandle('skutitle.txt', { create: true });
const w = await f.createWritable();
await w.write(useDesc);
await w.close();
}
let ok = 0;
for (let i = 0; i < urls.length; i++) {
try {
btn.innerText = `${i+1}/${urls.length}`;
const r = await axios.get(urls[i], { responseType: 'blob', timeout: 15000 });
const ext = urls[i].includes('.png') ? 'png' : urls[i].includes('.webp') ? 'webp' : 'jpg';
const f = await pd.getFileHandle(`media_${i}.${ext}`, { create: true });
const w = await f.createWritable();
await w.write(r.data);
await w.close();
ok++;
} catch (e) { console.error('媒体失败', i, e); }
}
btn.innerText = ot; btn.disabled = false;
clearEmbedded();
setStatusRed(`✅ ${ok}/${urls.length}`);
} catch (e) {
console.error('[下载]', e);
btn.innerText = ot; btn.disabled = false;
if (e.name !== 'AbortError') setStatusRed('❌ 下载出错');
}
}
// ───── 8. 启动 ─────
function mainExtract() {
extractProductInfo();
extractMainImages();
renderInfoPanel();
}
window.addEventListener('load', () => { if (CONFIG.autoRun) setTimeout(mainExtract, CONFIG.waitParseTime); });
GM_registerMenuCommand('🔍 手动提取', mainExtract);
GM_registerMenuCommand('📸 提取媒体图', extractMediaImages);
})();
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。