// ==UserScript==
// @name 批量下载贴吧原图
// @name:zh 批量下载贴吧原图
// @name:en Batch srcImage downloader for tieba
// @namespace https://github.com/Jeffrey-deng/userscript
// @version 3.4.2
// @description 一键打包下载贴吧中一贴的原图
// @description:zh 一键打包下载贴吧中一贴的原图
// @description:en Batch Download Src Image From Baidu Tieba
// @author Jeffrey.Deng
// @supportURL https://imcoder.site/a/detail/HuXBzyC
// @homepageURL https://imcoder.site
// @weibo http://weibo.com/3983281402
// @match http://tieba.baidu.com/*
// @match https://tieba.baidu.com/*
// @match http://imgsrc.baidu.com/*
// @match https://imgsrc.baidu.com/*
// @match http://tiebapic.baidu.com/*
// @match https://tiebapic.baidu.com/*
// @connect baidu.com
// @connect bdimg.com
// @require https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js
// @require https://cdn.bootcss.com/toastr.js/2.1.3/toastr.min.js
// @require https://cdn.bootcss.com/jszip/3.1.5/jszip.min.js
// @resource toastr_css https://cdn.bootcss.com/toastr.js/2.1.3/toastr.min.css
// @grant GM.xmlHttpRequest
// @grant GM_xmlHttpRequest
// @grant GM_notification
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant GM_registerMenuCommand
// ==/UserScript==
// @更新日志
// v.3.4.1 2020.7.11 1.修复jQuery下载失败问题
// v.3.3 2020.6.3 1.修复图片被删除但页面仍能看到却下载不到的问题
// v.3.1 2020.5.26 1.支持只下载楼主
// 2.图片后缀名根据图片实际类型命名
// v.3.0 2020.5.21 1.支持下载多页
// 2.支持下载被吞掉的图
// v.2.6.1 2019.12.16 1.修改压缩包名称为帖子的标题
// 如果还是要以前的id作为压缩包名称,那么修改449行:"packNameBy": "title",
// 将 packNameBy 的值 title 修改为 id, 再按 ctrl + s 保存。
// v.2.6 2.19.12.16 1.修改图片域名为tiebapic.baidu.com时下载图片显示“你查看的图片不存在的”的问题
// v 2.5.1 2019.12.11 1.修复格式化数字排序未生效的问题
// V 2.5 2019.12.2 1.修改为toastr提示方式
// 2.采用队列下载
// V 2.4 2019.3.17 1.调整图片排序的命名,格式化数字(1显示为01),便于查看时顺序一样
// 2.edge会闪退,原因不知,未修复
// V 2.3 2018.5.31 1.兼容edge
// V 2.2 2018.4.7 1.调整匹配图片策略
// V 2.1 2018.4.2 1.调用Tampermonkey API 实现跨域下载,无需修改启动参数
// V 2.0 2018.4.1 1.压缩包内增加贴子地址txt
// 2.修复https不能下载
// V 1.9 2018.4.1 1.新增打包下载,图片重命名(需开启浏览器跨域)
// V 1.8 2018.3.31 1.修复BUG
// 2.可自定义输入文件名后缀
// V 1.7 2017.6.9 1.修复魅族等贴吧下载图标不显示的问题
// V 1.6 2017.6.5 1.提高下载的图片正确率
// V 1.5 2017.6.4 1.增加右键新标签打开图片直接打开原图
// V 1.4 2017.6.3 1.更新对 https 的支持
// 2.提高图片匹配成功率
(function (factory) {
factory(document, jQuery);
// console.time('ready_init_use_time');
// $().ready(function(){
// console.timeEnd('ready_init_use_time');
// factory(document, jQuery);
// });
})(function (document, $) {
var common_utils = (function (document, $) {
function parseURL(url) {
var a = document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':', ''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function () {
var ret = {},
seg = a.search.replace(/^\?/, '').split('&'),
len = seg.length, i = 0, s;
for (; i < len; i++) {
if (!seg[i]) {
continue;
}
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
hash: a.hash.replace('#', ''),
path: a.pathname.replace(/^([^\/])/, '/$1'),
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
segments: a.pathname.replace(/^\//, '').split('/')
};
}
function ajaxDownload(url, callback, args, tryTimes) {
tryTimes = tryTimes || 0;
var GM_download = GM.xmlHttpRequest || GM_xmlHttpRequest,
clearUrl = url.replace(/[&\?]?download_timestamp=\d+/, ''),
retryUrl = clearUrl + (clearUrl.indexOf('?') === -1 ? '?' : '&') + 'download_timestamp=' + new Date().getTime();
GM_download({
method: 'GET',
responseType: 'blob',
url: url,
onreadystatechange: function (responseDetails) {
if (responseDetails.readyState === 4) {
if (responseDetails.status === 200 || responseDetails.status === 304 || responseDetails.status === 0) {
var blob = responseDetails.response, size = blob && blob.size;
if (size && (size / 1024 >= 5)) {
callback(blob, args);
} else if (tryTimes++ == 3) {
callback(blob, args);
} else {
ajaxDownload(retryUrl, callback, args, tryTimes);
}
} else {
if (tryTimes++ == 3) {
callback(null, args);
} else {
ajaxDownload(retryUrl, callback, args, tryTimes);
}
}
}
},
onerror: function (responseDetails) {
if (tryTimes++ == 3) {
callback(null, args);
} else {
ajaxDownload(retryUrl, callback, args, tryTimes);
}
console.log(responseDetails.status);
}
});
/*try {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.onreadystatechange = function(evt) {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 0) {
callback(xhr.response, args);
} else {
callback(null, args);
}
}
};
xhr.send();
} catch (e) {
callback(null, args);
}*/
}
function fileNameFromHeader(disposition, url) {
var result = null;
if (disposition && /filename=.*/ig.test(disposition)) {
result = disposition.match(/filename=.*/ig);
return decodeURI(result[0].split("=")[1]);
}
return url.substring(url.lastIndexOf('/') + 1);
}
function downloadBlobFile(content, fileName) {
if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(content, fileName);
} else {
var aLink = document.createElement('a');
aLink.download = fileName;
aLink.style = "display:none;";
var blob = new Blob([content]);
aLink.href = window.URL.createObjectURL(blob);
document.body.appendChild(aLink);
if (document.all) {
aLink.click(); //IE
} else {
var evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
aLink.dispatchEvent(evt); // 其它浏览器
}
window.URL.revokeObjectURL(aLink.href);
document.body.removeChild(aLink);
}
}
function downloadUrlFile(url, fileName) {
var aLink = document.createElement('a');
if (fileName) {
aLink.download = fileName;
} else {
aLink.download = url.substring(url.lastIndexOf('/') + 1);
}
aLink.target = "_blank";
aLink.style = "display:none;";
aLink.href = url;
document.body.appendChild(aLink);
if (document.all) {
aLink.click(); //IE
} else {
var evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
aLink.dispatchEvent(evt); // 其它浏览器
}
document.body.removeChild(aLink);
}
function paddingZero(num, length) {
return (Array(length).join("0") + num).substr(-length);
}
/* Class: TaskQueue
* Constructor: handler
* takes a function which will be the task handler to be called,
* handler should return Deferred object(not Promise), if not it will run immediately;
* methods: append
* appends a task to the Queue. Queue will only call a task when the previous task has finished
*/
var TaskQueue = function (handler) {
var tasks = [];
// empty resolved deferred object
var deferred = $.when();
// handle the next object
function handleNextTask() {
// if the current deferred task has resolved and there are more tasks
if (deferred.state() == "resolved" && tasks.length > 0) {
// grab a task
var task = tasks.shift();
// set the deferred to be deferred returned from the handler
deferred = handler(task);
// if its not a deferred object then set it to be an empty deferred object
if (!(deferred && deferred.promise)) {
deferred = $.when();
}
// if we have tasks left then handle the next one when the current one
// is done.
if (tasks.length >= 0) {
deferred.fail(function () {
tasks = [];
});
deferred.done(handleNextTask);
}
}
}
// appends a task.
this.append = function (task) {
// add to the array
tasks.push(task);
// handle the next task
handleNextTask();
};
};
var context = {
"ajaxDownload": ajaxDownload,
"fileNameFromHeader": fileNameFromHeader,
"downloadBlobFile": downloadBlobFile,
"downloadUrlFile": downloadUrlFile,
"parseURL": parseURL,
"paddingZero": paddingZero,
"TaskQueue": TaskQueue
};
return context;
})(document, jQuery);
var options = {
"type": 2,
"isNeedConfirmDownload": true,
"useQueueDownloadThreshold": 0,
"suffix": null,
"callback": {
"parseLocationInfo_callback": function (location_info, options) {
return common_utils.parseURL(document.location.href);
},
"parseFiles_callback": function (location_info, options) {
// file.url file.folder_sort_index
// not folder_sort_index -> use fileName
var files = [];
return files;
},
"makeNames_callback": function (arr, location_info, options) {
var names = {};
var time = new Date().getTime();
names.zipName = "pack_" + time;
names.folderName = names.zipName;
names.infoName = null;
names.infoValue = null;
names.prefix = time;
names.suffix = options.suffix;
return names;
},
"beforeFilesDownload_callback": function (files, names, location_info, options, zip, main_folder) {
},
"beforeFileDownload_callback": function (file, location_info, options, zipFileLength, zip, main_folder, folder) {
},
"eachFileOnload_callback": function (blob, file, location_info, options, zipFileLength, zip, main_folder, folder) {
},
"allFilesOnload_callback": function (files, names, location_info, options, zip, main_folder) {
},
"beforeZipFileDownload_callback": function (zip_blob, files, names, location_info, options, zip, main_folder) {
common_utils.downloadBlobFile(zip_blob, names.zipName + ".zip");
}
}
};
var ajaxDownloadAndZipFiles = function (files, names, location_info, options) {
// GM_notification("开始下载~", names.zipName);
var notify_start = toastr.success("正在打包~", names.zipName, {
"progressBar": false,
"hideDuration": 0,
"showDuration": 0,
"timeOut": 0,
"closeButton": false
});
if (files && files.length > 0) {
var zip = new JSZip();
var main_folder = zip.folder(names.folderName);
var zipFileLength = 0;
var maxIndex = files.length;
var paddingZeroLength = (files.length + "").length;
if (names.infoName) {
main_folder.file(names.infoName, names.infoValue);
}
options.callback.beforeFilesDownload_callback(files, names, location_info, options, zip, main_folder);
var downloadFile = function (file, resolveCallback) {
return $.Deferred(function (dfd) {
var folder = file.location ? main_folder.folder(file.location) : main_folder;
var isSave = options.callback.beforeFileDownload_callback(file, location_info, options, zipFileLength, zip, main_folder, folder);
if (isSave !== false) {
common_utils.ajaxDownload(file.url, function (blob, file) {
var isSave = options.callback.eachFileOnload_callback(blob, file, location_info, options, zipFileLength, zip, main_folder, folder);
if (isSave !== false) {
if (file.fileName) {
folder.file(file.fileName, blob);
} else {
var suffix = names.suffix || file.url.substring(file.url.lastIndexOf('.') + 1);
file.fileName = names.prefix + "_" + common_utils.paddingZero(file.folder_sort_index, paddingZeroLength) + "." + suffix;
folder.file(file.fileName, blob);
}
}
dfd.resolveWith(file, [blob, folder, isSave]);
}, file);
} else {
dfd.resolveWith(file, [null, folder, false]);
}
}).done(function (blob, folder, isSave) {
zipFileLength++;
notify_start.find(".toast-message").text("正在打包~ 第 " + zipFileLength + " 张" + (isSave ? "" : "跳过"));
resolveCallback && resolveCallback(); // resolve延迟对象
if (zipFileLength >= maxIndex) {
var isDownloadZip = options.callback.allFilesOnload_callback(files, names, location_info, options, zip, main_folder);
if (isDownloadZip !== false) {
zip.generateAsync({type: "blob"}).then(function (content) {
options.callback.beforeZipFileDownload_callback(content, files, names, location_info, options, zip, main_folder);
});
// GM_notification({text: "打包下载完成!", title: names.zipName, highlight : true});
toastr.success("下载完成!", names.zipName, {"progressBar": false, timeOut: 0});
}
notify_start.css("display", "none").remove();
}
});
};
if (maxIndex < options.useQueueDownloadThreshold) {
// 并发数在useQueueDownloadThreshold内,直接下载
for (var i = 0; i < maxIndex; i++) {
downloadFile(files[i]);
}
} else {
// 并发数在useQueueDownloadThreshold之上,采用队列下载
var queue = new common_utils.TaskQueue(function (file) {
if (file) {
var dfd = $.Deferred();
downloadFile(file, function () {
dfd.resolve();
});
return dfd;
}
});
for (var j = 0; j < maxIndex; j++) {
queue.append(files[j]);
}
}
} else {
notify_start.css("display", "none").remove();
toastr.error("未解析到图片!", "错误", {"progressBar": false});
}
};
/** 批量下载 **/
function batchDownload(config) {
try {
options = $.extend(true, {}, options, config);
var location_info = options.callback.parseLocationInfo_callback(options);
var files = options.callback.parseFiles_callback(location_info, options);
if (!(files && files.promise)) {
files = $.when(files);
}
files.done(function (files) {
if (files && files.length > 0) {
if (!options.isNeedConfirmDownload || confirm("是否下载 " + files.length + " 张图片")) {
var names = options.callback.makeNames_callback(files, location_info, options);
options.location_info = location_info;
options.files = files;
options.names = names;
if (options.type == 1) {
urlDownload(files, names, location_info, options);
} else {
ajaxDownloadAndZipFiles(files, names, location_info, options);
}
}
} else {
toastr.error("未找到图片~", "");
}
}).fail(function (message) {
toastr.error(message, "错误");
});
} catch (e) {
// GM_notification("批量下载照片 出现错误!", "");
console.warn("批量下载照片 出现错误!, exception: ", e);
toastr.error("批量下载照片 出现错误!", "");
}
}
/** 下载 **/
function urlDownload(photos, names, location_info, options) {
GM_notification("开始下载~", names.zipName);
var index = 0;
var interval = setInterval(function () {
if (index < photos.length) {
var url = photos[index].url;
var fileName = null;
if (!names.suffix) {
fileName = names.prefix + "_" + (index + 1) + url.substring(url.lastIndexOf('.'));
} else {
fileName = names.prefix + "_" + (index + 1) + "." + names.suffix;
}
common_utils.downloadUrlFile(url, fileName);
} else {
clearInterval(interval);
return;
}
index++;
}, 100);
}
//右键新标签打开图片直接打开原图
function initRightClickOpenSource() {
var url = document.location.toString();
var m = null;
if (!(m = url.match(/^https?:\/\/(imgsrc|tiebapic)\.baidu\.com\/forum\/pic\/item\/.+/i))) {
if ((m = url.match(/^(https?):\/\/(imgsrc|imgsa|tiebapic|\w+\.hiphotos)\.(?:bdimg|baidu)\.com\/(?:forum|album)\/.+\/(\w+\.(?:jpg|jpeg|gif|png|bmp|webp))(?:\?.+)?$/i))) {
document.location = m[1] + "://" + (m[2] == "tiebapic" ? "tiebapic" : "imgsrc") + ".baidu.com/forum/pic/item/" + m[3];
}
}
}
/*** start main ***/
//右键新标签打开图片直接打开原图
initRightClickOpenSource();
var getReplyAuthorUid = function ($reply) { // 获取回复UID
let userInfoStr = $reply.find('.d_name').attr('data-field');
return (userInfoStr && userInfoStr.match(/"user_id":(\d+)/) && RegExp.$1) || 0;
}
var getPostAuthorUid = function () { // 获取楼主UID
return getReplyAuthorUid($('#j_p_postlist').children('.j_l_post').first());
}
// css
GM_addStyle(GM_getResourceText('toastr_css'));
// 添加按钮
var $lis_nav = $('#tb_nav').find('ul').eq(0).find('li'),
li_count = $lis_nav.length,
$li_right = $lis_nav.eq(li_count - 1),
html = '';
if ($li_right.hasClass('none_right_border')) {
var isStarTie = $li_right.hasClass('star_nav_tab');
if (isStarTie) {
html = '<li class="none_right_border star_nav_tab" style="cursor: pointer"><div class="star_nav_tab_inner"><div class="space">' +
'<a title="点击下载本页图片" class="star_nav_ico star_nav_ico_photo" id="batchDownloadBtn"><i class="icon"></i>下载</a></div></div></div>';
} else {
html = '<li class="none_right_border j_tbnav_tab" style="cursor: pointer"><div class="tbnav_tab_inner"><p class="space">' +
'<a title="点击下载本页图片" class="nav_icon icon_jingpin j_tbnav_tab_a" id="batchDownloadBtn" location="tabplay" >下载</a></p></div></div>';
}
$li_right.removeClass('none_right_border').after(html);
} else {
html = '<li class="j_tbnav_tab" style="cursor: pointer"><a class="j_tbnav_tab_a" id="batchDownloadBtn">下载</a> </li>';
$li_right.after(html);
}
// 仪表盘控制栏添加按钮
GM_registerMenuCommand('下载图片', function() {
tiebaImagesDownload();
});
GM_registerMenuCommand('只下楼主', function() {
tiebaImagesDownload({"onlyLz": true});
});
$('#batchDownloadBtn').click(function () {
tiebaImagesDownload({"onlyLz": (document.location.href.indexOf('see_lz=1') !== -1 && confirm("是否只下载楼主的图片"))});
});
var tiebaImagesDownload = unsafeWindow.tiebaImagesDownload = function (options) {
var config = {
"type": 2,
"minWidth": 100,
"suffix": null,
"packNameBy": "title", // "id" or "title"
"baiduLoadPhotosApi": "https://tieba.baidu.com/photo/bw/picture/guide",
"findPhotoByApi": true,
"onlyLz": false,
"callback": {
"parseFiles_callback": function (location_info, options) {
let pn = location_info.params.pn || 1,
authorUid = getPostAuthorUid(),
findPhotosByPage = function () {
let photo_arr = [],
$part_nodes_one = $('.d_post_content,.d_post_content_main').find("img");
//var part_nodes_two = $('.d_post_content_main,.post_bubble_middle,.d_post_content').find("img");
$.each($part_nodes_one, function (i, img) {
let $img = $(img);
if (options.onlyLz) { // 只下楼主
let replyUid = getReplyAuthorUid($img.closest('.j_l_post'));
if (replyUid != authorUid) {
return;
}
}
// 如果是广告图片则跳过
if (img.parentNode.tagName == "A" && img.parentNode.className.indexOf("j_click_stats") != -1) {
return true;
}
if (img.clientWidth >= options.minWidth) {
if ($img.hasClass("BDE_Image") || $img.hasClass("d_content_img")) {
var photo = {};
photo.location = "";
var thumb_url = img.src;
photo.folder_sort_index = photo_arr.length + 1;
// 如果是用户上传的图片
if ($img.attr("pic_type") == "0") {
var urlMatcher = thumb_url.match(/^(https?):\/\/([a-zA-Z]+)\..*\/([^/]+)$/);
photo.url = urlMatcher[1] + "://" + (urlMatcher[2] == "tiebapic" ? "tiebapic" : "imgsrc") + ".baidu.com/forum/pic/item/" + urlMatcher[3];
photo.id = urlMatcher[3].match(/^[^.]+/)[0];
}
// 如果是用户引用的图片
else {
var m = thumb_url.match(/^(https?):\/\/(imgsrc|imgsa|tiebapic|\w+\.hiphotos)\.(?:bdimg|baidu)\.com\/(?:forum|album)\/.+\/((\w+)\.(?:jpg|jpeg|gif|png|bmp|webp))(?:\?.+)?$/i);
// 如果引用的是贴吧图片
if (m !== null) {
photo.url = m[1] + "://" + (m[2] == "tiebapic" ? "tiebapic" : "imgsrc") + ".baidu.com/forum/pic/item/" + m[3];
photo.id = m[4];
} else {
photo.url = thumb_url;
}
}
photo.size = $img.attr("size") || 0;
photo.location = "photos";
photo_arr.push(photo);
}
}
});
return photo_arr;
};
let notify_photo_data_loading = toastr.success("正在请求图片数据~", "", {
"progressBar": false,
"hideDuration": 0,
"showDuration": 0,
"timeOut": 0,
"closeButton": false
});
return $.Deferred(function (finalDfd) {
if (options.findPhotoByApi) {
let photo_arr = [], curr_load_count = 0, loadQueue = new common_utils.TaskQueue(function (startPicId) {
return $.Deferred(function (dfd) {
$.get(options.baiduLoadPhotosApi, {
'tid': location_info.file,
'see_lz': options.onlyLz ? 1 : 0, // 只下楼主
'from_page': 0,
// 'alt': 'jview',
'next': 50,
'prev': 0,
'pic_id': startPicId,
'_': new Date().getTime(),
}, function (resp) {
let data = resp.data;
if (data && data.pic_list) {
let pic_amount = data.pic_amount,
pic_list = data.pic_list,
lastPicId,
startPushPic = false;
$.each(pic_list, function (key, pic) {
let original = pic.img.original, photo;
switch (true) {
case original.id == startPicId:
startPushPic = true;
break;
case !startPicId:
startPushPic = true;
case startPushPic:
photo = {};
photo.location = "photos";
photo.folder_sort_index = photo_arr.length + 1;
photo.id = original.id;
photo.url = (original.waterurl && original.waterurl.replace(/^http:\/\//, 'https://')) ||
(`https://imgsrc.baidu.com/forum/pic/item/${original.id}.jpg`);
photo.size = original.size;
photo_arr.push(photo);
curr_load_count++;
lastPicId = original.id;
}
});
if (lastPicId && curr_load_count < pic_amount) {
loadQueue.append(lastPicId);
} else {
// 队列下载结束
// 对比页面数据和api返回数据,两者合并结果,并尝试按页面显示顺序排序
let combine_photo_arr = [],
page_photo_arr = findPhotosByPage().filter(function(photo) {
return photo.size != 0; // 有些页面图片没写size,所以这里过滤了没写size的,暂时先这样处理
}).map(function(photo) {
let has_delete = true;
if (photo.id) {
for (let p of photo_arr) {
// 由于同样一张图片,id有两个,这里采用对比文件大小的方式来确定是否同一张图片
if (p.id == photo.id || (p.size != 0 && p.size == photo.size)) {
has_delete = false;
break;
}
}
}
photo.has_delete = has_delete;
return photo;
}),
pageLength = page_photo_arr.length,
serverLength = photo_arr.length,
hasDeleteLength = page_photo_arr.filter(function(photo) {
return photo.has_delete;
}).length;
if (hasDeleteLength > 0) {
let start_left_index = 0, start_right_index = 0, unshift_length = 0, i, j,
photo_url_arr = photo_arr.map(function (photo) {
return photo.url;
});
pn > 1 && $.each(page_photo_arr, function(i, photo) {
let index = photo_url_arr.indexOf(photo.url);
if (index != -1) {
start_right_index = index;
start_left_index = i;
return false;
} else {
unshift_length++;
}
});
if (start_right_index > 0) {
combine_photo_arr.push.apply(combine_photo_arr, photo_arr.slice(0, start_right_index));
}
if (start_left_index > 0) {
combine_photo_arr.push.apply(combine_photo_arr, page_photo_arr.slice(start_left_index - unshift_length, start_left_index));
}
for (i = start_left_index, j = start_right_index; i < pageLength && j < serverLength;) {
let photo, left = page_photo_arr[i], right = photo_arr[j];
if (left.id === right.id || (left.size != 0 && left.size == right.size)) {
photo = right;
i++;
j++;
} else {
if (left.has_delete) {
photo = left;
i++;
} else {
photo = right;
j++;
}
}
combine_photo_arr.push(photo);
}
if (i <= pageLength - 1) {
combine_photo_arr.push.apply(combine_photo_arr, page_photo_arr.slice(i, pageLength));
}
if (j <= serverLength - 1) {
combine_photo_arr.push.apply(combine_photo_arr, photo_arr.slice(j, serverLength));
}
$.each(combine_photo_arr, function(i, photo) {
photo.folder_sort_index = i + 1;
});
} else {
combine_photo_arr = photo_arr;
}
finalDfd.resolve(combine_photo_arr);
}
dfd.resolve();
} else {
dfd.reject('api返回错误');
}
}, 'json').fail(function () {
dfd.reject('api返回错误');
});
}).fail(function (msg) {
console.warn(msg);
options.findPhotoByApi = false;
finalDfd.resolve(findPhotosByPage());
});
});
loadQueue.append(null);
} else {
finalDfd.resolve(findPhotosByPage());
}
}).always(function () {
notify_photo_data_loading.css("display", "none").remove();
});
},
"makeNames_callback": function (photos, location_info, options) {
var names = {},
tie_id = location_info.file,
pn = location_info.params.pn || 1,
title = $(".core_title_txt").attr("title"),
forum = ($('#container').find('.card_title a.card_title_fname').text() || '贴').replace(/^\s*|\s*$/g, '');
names.infoName = "tie_info.txt";
names.infoValue = "id:" + tie_id + "\r\n" +
"title:" + title + "\r\n" +
"url:" + location_info.source + "\r\n" +
"page:" + pn + "\r\n" +
"image_amount:" + photos.length + "\r\n";
names.zipName = (options.packNameBy == "id" ? ("tie_" + tie_id) : (forum + '_' + tie_id + '_' + title)) + ((options.findPhotoByApi || pn == 1) ? "" : ("_" + pn));
names.folderName = names.zipName;
names.prefix = tie_id + (options.findPhotoByApi ? "" : ("_" + common_utils.paddingZero(pn, 3)));
names.suffix = options.suffix;
names.tie = {
'id': tie_id,
'title': title,
'pn': pn,
'forum': forum
};
return names;
},
"beforeFilesDownload_callback": function (photos, names, location_info, options, zip, main_folder) {
const paddingZeroLength = (photos.length + "").length;
$.each(photos, function (i, photo) {
photo.fileName = names.prefix + "_" + common_utils.paddingZero(photo.folder_sort_index, paddingZeroLength) + "." + (names.suffix || photo.url.substring(photo.url.lastIndexOf('.') + 1));
});
options.failFiles = undefined;
},
"eachFileOnload_callback": function (blob, photo, location_info, options, zipFileLength, zip, main_folder, folder) {
if (blob == null) {
if (!options.failFiles) {
options.failFiles = [];
}
options.failFiles.push(photo);
} else if (!options.names.suffix && photo.location == 'photos' && blob.type && blob.type.indexOf('image/') === 0) {
// 如果没有指定后缀名,那么后缀根据content-type来判断
let suffixRegex = /\.[^.]+$/, suffix = ('.' + blob.type.replace('image/', '').replace('jpeg', 'jpg'));
photo.fileName = photo.fileName.replace(suffixRegex, suffix);
photo.url = photo.url.replace(suffixRegex, suffix);
}
return true;
},
"allFilesOnload_callback": function (photos, names, location_info, options, zip, main_folder) {
let photo_urls_str = "", failPhotoListStr = "";
// 链接列表文件
$.each(photos, function (i, photo) {
photo_urls_str += ((photo.location ? (photo.location + "/") : "" ) + photo.fileName) + "\t" + photo.url + "\r\n";
});
main_folder.file("photo_url_list.txt", photo_urls_str);
// 帮助文件
main_folder.file("帮助.txt", "有些图片可能下载下来是裂掉的缩略图,可以从photo_url_list.text中按文件名手动找到链接下载。");
// 失败链接列表
if (options.failFiles && options.failFiles.length > 0) {
toastr.error("共 " + options.failFiles.length + " 张下载失败,已记录在photos_fail_list.txt!", "", {"progressBar": false, timeOut: 0});
failPhotoListStr = "";
for (var i in options.failFiles) {
var failFile = options.failFiles[i];
failPhotoListStr += (failFile.location + "/" + failFile.fileName + "\t" + failFile.url + "\r\n");
}
main_folder.file("photos_fail_list.txt", failPhotoListStr);
}
}
}
};
if (options) {
$.extend(true, config, options);
}
batchDownload(config);
};
});