// ==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;
}
})();