// ==UserScript== // @name 电商主图和视频一键下载,支持1688,淘宝,天猫,拼多多 // @namespace https://scriptcat.org/zh-CN/users/161051 // @version 1.0 // @description 在主流电商详情页添加按钮,一键下载主图和视频。(使用前,请保证你有权使用这个素材。) // @author 定制功能请加微信: ponysixty // @match *://*.yangkeduo.com/* // @match *://*.pinduoduo.com/* // @match https://detail.1688.com/offer/* // @match https://detail.tmall.com/item.htm* // @match https://item.taobao.com/item.htm* // @grant none // ==/UserScript== (function() { 'use strict'; // 创建按钮 const button = document.createElement('button'); button.textContent = '一键下载主图和视频'; button.style.position = 'fixed'; button.style.top = '0'; button.style.right = '0'; // button.style.width = '-166px'; // button.style.height = '42px'; // button.style.left = '-160px'; // button.style.transition = 'left 0.3s ease-in-out'; // button.addEventListener('mouseenter', () => button.style.left = '0'); // button.addEventListener('mouseleave', () => button.style.left = '-160px'); button.style.backgroundColor = 'red'; button.style.color = 'white'; button.style.padding = '10px 20px'; button.style.border = 'none'; button.style.borderRadius = '5px'; button.style.cursor = 'pointer'; // 添加按钮到页面 const targetElement = document.querySelector('body'); // 根据实际页面结构调整 targetElement.appendChild(button); // 按钮点击事件 button.addEventListener('click', () => { let carouselImages = []; // 轮播图图片数组 let video = ''; // 视频元素 let name = ''; // 下载name if (window.location.href.includes('yangkeduo.com') || window.location.href.includes('pinduoduo.com')) { // 提取轮播图图片 carouselImages = document.querySelectorAll('.goods-container-v2 > div:first-child img'); // 提取视频 video = document.querySelector('.goods-container-v2 > div:first-child video'); // 提取商品id const url = new URL(window.location.href); name = url.searchParams.get("goods_id") || Date.now(); // 提取主图 carouselImages.forEach((img, index) => { const imgUrl = img.src; console.log(index,imgUrl); // 调试用,可删除 imgUrl && downloadFile(imgUrl, `${name}_img_${index + 1}.jpg`); }); // 提取视频 if (video) { const videoUrl = video.src; console.log('videoUrl: ',videoUrl); // 调试用,可删除 videoUrl && downloadFile(videoUrl, `${name}_video.mp4`); } } else if (window.location.href.includes('detail.1688.com')) { // 提取主图和视频 carouselImages = document.querySelectorAll('#gallery img'); video = document.querySelector('#gallery video'); name = window.location.pathname.replace('/offer', '').replace('.html', '').replace('/', ''); carouselImages.forEach((img, index) => { let imgUrl = img.src; console.log(index,imgUrl); // 调试用,可删除 imgUrl = imgUrl.replace(/_b.jpg$/, ''); imgUrl && downloadFile(imgUrl, `${name}_img_${index + 1}.jpg`); }); if (video) { const videoUrl = video.src; console.log(videoUrl); // 调试用,可删除 videoUrl && downloadFile(videoUrl, `${name}_video.mp4`); } } else if (window.location.href.includes('detail.tmall.com') || window.location.href.includes('item.taobao.com')) { // 提取主图和视频 carouselImages = document.querySelectorAll('.pageContentWrap ul>li>img'); video = document.querySelector('.pageContentWrap video'); const url = new URL(window.location.href); name = url.searchParams.get("id") || Date.now(); carouselImages.forEach((img, index) => { let imgUrl = img.src; console.log(index, imgUrl); // 调试用,可删除 imgUrl = imgUrl.replace(/_.webp$/, ''); imgUrl && downloadFile(imgUrl, `${name}_img_${index + 1}.jpg`); }); if (video) { const videoUrl = video.src; console.log(videoUrl); // 调试用,可删除 videoUrl && downloadFile(videoUrl, `${name}_video.mp4`); } } }); const triggerDownload = (name, blob) => { // 创建 Blob 对象的 URL const blobUrl = URL.createObjectURL(blob); // 创建一个临时链接元素 const tempLink = document.createElement("a"); tempLink.href = blobUrl; tempLink.download = name; // 将链接添加到 DOM 并模拟点击 document.body.appendChild(tempLink); // 避免某些浏览器安全限制 tempLink.click(); // 清理临时链接元素 document.body.removeChild(tempLink); // 从 DOM 中移除临时链接 URL.revokeObjectURL(blobUrl); // 释放 URL console.info(`文件已成功下载: ${name}`); } const downloadFile = async (link, name, trigger = true, retries = 5) => { if (!link) { return false; } //使用URL中的goods_id作为文件名 for (let attempt = 1; attempt <= retries; attempt++) { try { // 使用 fetch 获取文件数据 const response = await fetch(link, {method: "GET"}); // 检查响应状态码 if (!response.ok) { console.error(`下载失败,状态码: ${response.status},URL: ${link},尝试次数: ${attempt}`); continue; // 继续下一次尝试 } const blob = await response.blob(); if (trigger) { triggerDownload(name, blob); return true; } else { return blob; } } catch (error) { console.error(`下载失败 (${name}),错误信息:`, error, `尝试次数: ${attempt}`); if (attempt === retries) { return false; // 如果达到最大重试次数,返回失败 } } } return false; // 如果所有尝试都失败,返回失败 }; })();