淘宝天猫图片打包下载

主图、SKU、详情和视频打包下载

// ==UserScript==
// @name         淘宝天猫图片打包下载
// @version      0.6.0.1
// @description  主图、SKU、详情和视频打包下载
// @author       lelf2005(原作者)suren_chan(修改)
// @match        *://item.taobao.com/*
// @match        *://detail.tmall.com/*
// @include      https://item.taobao.com/item.htm?*
// @include      https://detail.tmall.com/item.htm?*
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @require      https://cdn.bootcss.com/materialize/1.0.0-rc.2/js/materialize.min.js
// @require      https://cdn.bootcss.com/jszip/3.2.2/jszip.min.js
// @require      https://cdn.jsdelivr.net/npm/file-saver@2.0.2/dist/FileSaver.min.js
// @require      https://cdn.bootcss.com/jszip-utils/0.1.0/jszip-utils.min.js
// @resource     lelf-materialcss https://cdn.jsdelivr.net/gh/lelf2005/cdn@master/material.css?v=20200630
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @license      MIT
// @namespace https://greasyfork.org/users/786427
// ==/UserScript==

(function() {
	'use strict';
	var $ = $ || window.$;
	var materialcss = GM_getResourceText('lelf-materialcss');
	GM_addStyle(materialcss);
	addMenu();
	var zipImgs;
	var zipDetailImgs;
	let splitImgZip
    
//=====<-在详情页面添加下载图标->=====

	function addMenu() {
		var DLBtn = `
			<div class="fixed-action-btn">
				<a id="lelf_tb" class="btn-floating light-blue darken-3 modal-trigger" style="left: -50px;" href="#lelf_modal2" title="详情打包下载">
					<div class="lelf-icon-download"></div>
				</a>
			</div>`;
		$("body").append(DLBtn);//用append在body内加入DLBtn
		$("#lelf_tb").click(function(){
			getTBPics();//获取所有图片
			$('#lelf_modal2').modal();//打开弹窗
		});
	}
	
//=====<-获取所有内容->=====

	function getTBPics(){
		zipImgs = [];//定义压缩包内主图、SKU图片数组
		zipDetailImgs = [];//定义压缩包内详情页图片数组
		var mainVideoHtml = '';//定义视频代码
		var imgHtml = '';//定义主图html代码
		var skuImgHtml = '';//定义SKU图html代码
		var detailImgHtml = '';//定义详情页html代码
		var imgSrc = '';//定义主图地址
		var skuImgSrc = '';//定义SKU图地址
		var detailImgSrc = '';//定义详情页图片地址
		var NewOROld = document.getElementById("J_SiteNav");//通过旧版ID:J_SiteNav定义判断值
		
		//=====<-判断新旧版本并获取资源位置->=====
		
		var isBlobVideo = false;
		if(NewOROld){
			var mainVideo = $("video").find("source");//旧版视频位置
			var mainImg = $("#J_UlThumb").find("img");//旧版主图位置
			var skuImg = $(".tb-sku .tm-img-prop").find("a");//旧版SKU图位置
			var detailImg = $("#description > .content").find("img");//旧版详情页位置
  		}
  		else{
  			var mainVideo = $(".lib-video").find("video");//新版视频位置
  			var mainImg = $("ul").find("img");//新版主图位置
  			var skuImg = $(".skuCate").find("img");//新版SKU位置
  			var detailImg = $(".desc-root").find("img");//新版详情页位置
  		}
		
		//=====<-获取视频内容->=====
		
		if(mainVideo.length > 0){
			mainVideo[0].src = mainVideo[0].src.substring(0, mainVideo[0].src.lastIndexOf("?"));
			mainVideoHtml = ''+
'				<div class="row" style="margin-left:0px;margin-top:10px;background-color:rgba(0, 0, 0, 0.1);"><p style="font-size:24px;margin-left:10px;">| 主图视频:</p></div>'+
'				<div class="row" style="margin-left:10px;">'+
'					<video class="responsive-video" width="300" height="400" style="border-radius: 10px;" controls>'+
'						<source src="'+mainVideo[0].src+'" type="video/mp4">'+
'					</video>'+
'				</div>';
			zipImgs.push(mainVideo[0].src);//将视频放入压缩包
		}
		else if($("video").length > 0){
			mainVideoHtml = '<div class="row" style="margin-left:0px;margin-top:10px;background-color:rgba(0, 0, 0, 0.1);"><p style="color:#888888;font-size:24px;margin-left:10px;text-decoration: line-through;">| 糟糕!视频被藏起来了!</p></div>';
		}
		
		//=====<-获取主图内容->=====
		
		for(var i =0; i< mainImg.length;i++){
			imgSrc = mainImg[i].src;
			if(imgSrc.lastIndexOf("webp")>-1){
				imgSrc = imgSrc.substring(0, imgSrc.lastIndexOf('_', imgSrc.lastIndexOf('_') - 1));
			}
			else{
				imgSrc = imgSrc.substring(0, imgSrc.lastIndexOf("_"));
			}
			zipImgs.push(imgSrc);//将主图放入压缩包
			imgHtml += '<div class="col s2"><img class="materialboxed" style="width:100%;border-radius: 10px;margin: 10px;" src="'+imgSrc+'"></div>';
		}
		
		//=====<-获取SKU内容->=====
		
		if(NewOROld){
			if(skuImg.length == 0){//旧版
				skuImg = $(".tb-skin .tb-img").find("a");
			}
			for(var n =0; n< skuImg.length;n++){
				if(skuImg[n].style.background){
					skuImgSrc = skuImg[n].style.background.split("(")[1].split(")")[0];
					skuImgSrc = skuImgSrc.substring(1,skuImgSrc.lastIndexOf("_"));
					zipImgs.push(skuImgSrc);//将SKU图放入压缩包
					skuImgHtml += '<div class="col s2"><img class="materialboxed" style="width:100%;padding:10px;" src="'+skuImgSrc+'"></div>';
				}
			}
		}
		else{
			for(var i =0; i< skuImg.length;i++){//新版
				skuImgSrc = skuImg[i].src;
				if(skuImgSrc.lastIndexOf("webp")>-1){
					skuImgSrc = skuImgSrc.substring(0, skuImgSrc.lastIndexOf('_', skuImgSrc.lastIndexOf('_') - 1));
				}
				else{
					skuImgSrc = skuImgSrc.substring(0, skuImgSrc.lastIndexOf("_"));
				}
				zipImgs.push(skuImgSrc);//将SKU图放入压缩包
				skuImgHtml += '<div class="col s2"><img class="materialboxed" style="width:100%;border-radius: 10px;margin: 10px;" src="'+skuImgSrc+'"></div>';
			}
		}
		
		//=====<-获取详情页内容->=====
		
		for(var k =0; k< detailImg.length;k++){
			if(detailImg[k].getAttribute("data-ks-lazyload") !== null){
				detailImgSrc = detailImg[k].getAttribute("data-ks-lazyload");
			}
			else{
				detailImgSrc = detailImg[k].src;
            }
			if(detailImg[k].naturalWidth > 100 ){
				zipDetailImgs.push(detailImgSrc);//将详情图放入压缩包
				detailImgHtml += '<div class="col s12"><img class="materialboxed" style="width:790px;margin: auto;" src="'+detailImgSrc+'"></div>';
				}
		}
		addTBHtml(mainVideoHtml,imgHtml,skuImgHtml,detailImgHtml);
		$('.materialboxed').materialbox();
	}

//=====<-将内容在弹窗内展现->=====	
		
    function addTBHtml(video,imgs,skuImgs,detailImgs){
		var isAdded = $("#lelf_modal2");
		if(isAdded.length > 0){
			isAdded.remove();
		}
		var s = ''+
			'<div id="lelf_modal2" class="modal modal-fixed-footer" style="height:100%;max-height:80%;">'+
			'	<div class="modal-content">'+
			'	<h4 class="h4" style="text-align: center;">——  详情套图打包下载工具  ——</h4>'+
			'	<div class="row">'+
			'		<div class="col s12">'+
			'			<ul class="tabs">'+
			'				<li class="tab col s2"><a class="active" href="#main_pics">视频、主图、SKU图</a></li>'+
			'				<li class="tab col s2"><a  href="#detail_pics">详情页预览</a></li>'+
			'				<li class="tab col s2"><a  href="#detail_pics_splitter">切片合并</a></li>'+
			'			</ul>'+
			'		</div>'+
			'		<div id="main_pics" class="col s12">'+video+'<div class="row" style="margin-left:0px;margin-top:10px;background-color:rgba(0, 0, 0, 0.1);">'+
			'			<p style="font-size:24px;margin-left:10px;">| 主图:</p></div>'+
			'			<div class="row">'+imgs+'</div>'+
			'			<div class="row" style="margin-left:0px;margin-top:10px;background-color:rgba(0, 0, 0, 0.1);">'+
			'				<p style="font-size:24px;margin-left:10px;">| SKU图:</p>'+
			'			</div>'+
			'			<div class="row">'+skuImgs+'</div>'+
			'		</div>'+
			'		<div id="detail_pics" class="col s12">'+detailImgs+'</div>'+
			'		<div id="detail_pics_splitter" class="col s12">'+
			'			<div style="display:flex;justify-content:center;margin:10px;align-items:center;">'+
			'				<a class="waves-effect waves-light btn" style="margin-right:10px;margin-top:10px;font-size:24px;" id="mergeImgs">合并成长版</a>'+
			'			</div>'+
			'		<div style="display:flex;justify-content:center;margin:10px;align-items:start;">'+
			'			<div id="mergePreview"></div>'+
			'		</div>'+
			'	</div>'+
			'	<canvas id="mycanvas" style="display:none;"></canvas>'+
			'</div>'+
			'</div>'+
			'	<div class="modal-footer">'+
			'		<a href="#!" id="lelf-msg" class="modal-close waves-effect waves-green btn-flat"></a>'+
			'		<a id="lelf_tbpic_download" class="waves-effect waves-light btn">下载</a>'+
			'		<a href="#!" class="modal-close waves-effect red lighten-1 waves-green btn-flat">关闭</a>'+
			'	</div>'+
			'</div>';
		$("body").append(s);//向body内插入上述代码
		var instance = M.Tabs.init($('.tabs'), '{}');
		$('.tabs').tabs('updateTabIndicator');
        var itemId = window.location.href.split("id=")[1].split('&')[0];
            if(itemId === null && itemId.toString().length<0){
                itemId="unknown";
            }
		$("#lelf_tbpic_download").click(function(){
			var zip = new JSZip();
			var mainImgs = zip.folder("main");
			var detailImgs = zip.folder("detail");
			var suffix = '';
			var totalAssets = zipImgs.length + zipDetailImgs.length;
			var currentAsset = 0;
			for(var i=0;i<zipImgs.length;i++){
				suffix = zipImgs[i].substring(zipImgs[i].lastIndexOf(".") + 1, zipImgs[i].length);
				mainImgs.file(i.toString()+'.'+suffix, urlToPromise(zipImgs[i]), {binary:true});
				currentAsset++;
				$("#lelf-msg").text("处理中:"+currentAsset+"/"+totalAssets);
			}
			for(var j=0;j<zipDetailImgs.length;j++){
				suffix = zipDetailImgs[j].substring(zipDetailImgs[j].lastIndexOf(".") + 1, zipDetailImgs[j].length);
				detailImgs.file(j.toString()+'.'+suffix, urlToPromise(zipDetailImgs[j]), {binary:true});
				currentAsset++;
				$("#lelf-msg").text("处理中:"+currentAsset+"/"+totalAssets);
			}
			
			zip.generateAsync({type:"blob"})
				.then(function callback(blob) {
				$("#lelf-msg").text("打包中:"+currentAsset+"/"+totalAssets);
				saveAs(blob, itemId+".zip");
				$("#lelf-msg").text("已完成:"+currentAsset+"/"+totalAssets);
			});
		});
		$('#mergeImgs').click(function(){
			let merger = new Merger(document.getElementById('mycanvas'), Image);
			merger.merge(zipDetailImgs, imgPreview);
			document.getElementById("splitImg").classList.remove('disabled');
		});
	}
	function urlToPromise(url) {
		return new Promise(function(resolve, reject) {
			JSZipUtils.getBinaryContent(url, function (err, data) {
				if(err) {
					reject(err);
				}
				else {
					resolve(data);
				}
			});
		});
	}
	

	class Merger {
		constructor(canvas, Image) {
			this.canvas = canvas;
			this.Image = Image;
			this.ctx = this.canvas.getContext("2d");
		}
		
		async merge(urls, cb) {
			const imgs = await this.loadImages(urls);
			const map = [];
			const gap = 0;
			const scale = 1;
			const maxWidth = imgs.reduce((m, x) => Math.max(m, x.width), 0);
			const maxHeight = imgs.reduce((m, x) => m + x.height + gap, 0);
			let canvash = 0;
			for (let i = 0; i < urls.length; i += 1) {
				const url = urls[i];
				const { width , height } = imgs[i] ;
				canvash += (height / width) * 790 + gap;
			}
			this.canvas.width = 790;
			this.canvas.height = canvash;
			let y = 0;
			const x = 0;
			for (let i = 0; i < urls.length; i += 1) {
				const url = urls[i];
				let name = "";
				if (typeof File === "function" && url instanceof File) {
					name = url.name.split(".").shift();
				} else {
					name = url
					.split("/")
					.pop()
					.split(".")
					.shift();
				}
				const { width , height } = imgs[i] ;
				this.ctx.drawImage(imgs[i], x, y, 790, (height / width) * 790);
				map.push([name, x, y, width, height]);
				y += (height / width) * 790 + gap;
			}
			cb();
		}
		
		loadImages(urls) {
			const imgs = [];
			let count = 0;
			const { length } = urls;
			return new Promise((resolve, reject) => {
			for (let i = 0; i < urls.length; i += 1) {
				const img = new this.Image();
				img.setAttribute("crossOrigin",'Anonymous')
				const url = urls[i];
				img.onerror = reject;
				img.onload = () => {
					imgs[i] = img;
					count += 1;
					if (count === length) resolve(imgs);
				};
				if (typeof File === "function" && url instanceof File) {
					const reader = new FileReader();
					reader.addEventListener(
						"load",
						() => {
							img.src = reader.result;
						},
						false
					);
					reader.readAsDataURL(url);
				} else {
				img.src = url;
				}
			}
			});
		}
	}
	
	function imgPreview(){
		const preview = document.createElement('img');
		preview.src = document.getElementById("mycanvas").toDataURL();
		preview.style.width = "100%";
		preview.style.border = "1px solid #a2de96";
		document.getElementById("mergePreview").appendChild(preview);
		$('#mergeImgs').html('长版详情分辨率:('+document.getElementById("mycanvas").width+'*'+document.getElementById("mycanvas").height+') / 右键另存为');
	}
	
	

    // Your code here...
function getQueryString(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return r[2];
        return null;
    }
    var site = window.location.href.match(/^http(s)?:\/\/[^?]*/);
    var wd = getQueryString("wd");
    var id = getQueryString("id");
    var q = getQueryString("q");
    var pureUrl;
    if (wd != null) {
        pureUrl = site[0] + "?wd=" + wd;
    } else if (id != null) {
        pureUrl = site[0] + "?id=" + id;
    } else if (q != null) {
        pureUrl = site[0] + "?q=" + q;
    } else if (site[0].substr(site[0].length - 13) == "view_shop.htm") {
        pureUrl = window.location.protocol + "//" + window.location.host;
    } else {
        pureUrl = site[0];
    }
    if(pureUrl != window.location.href){
        window.history.pushState({},0,pureUrl);
        //window.location.href = pureUrl;
    }

})();