// ==UserScript==
// @name Lofter(乐乎)原图下载 修改版
// @namespace LofterSpiderFix
// @license MIT
// @version 1.0.2
// @author Kaesinol
// @author 兰陵笑笑生
// @homepage https://gist.github.com/kaixinol/3652d2484de12818e9b402808db30801
// @description 批量下载Lofter图片,修改自 [Lofter原图查看下载](https://greasyfork.org/zh-CN/scripts/32942-lofter-%E4%B9%90%E4%B9%8E-%E5%8E%9F%E5%9B%BE%E6%9F%A5%E7%9C%8B%E4%B8%8B%E8%BD%BD)
// @match https://*.lofter.com/post/*
// @grant GM_xmlhttpRequest
// @require https://update.greasyfork.icu/scripts/473358/1237031/JSZip.js
// @downloadURL https://update.greasyfork.icu/scripts/524687/Lofter%28%E4%B9%90%E4%B9%8E%29%E5%8E%9F%E5%9B%BE%E4%B8%8B%E8%BD%BD%20%E4%BF%AE%E6%94%B9%E7%89%88.user.js
// @updateURL https://update.greasyfork.icu/scripts/524687/Lofter%28%E4%B9%90%E4%B9%8E%29%E5%8E%9F%E5%9B%BE%E4%B8%8B%E8%BD%BD%20%E4%BF%AE%E6%94%B9%E7%89%88.meta.js
// ==/UserScript==
(function () {
"use strict";
var css = document.createElement("style");
css.id = "spidercss";
var cssText =
"#spiderboprt{position:fixed;top:7px;right:15px;margin:0 5px 0 0;z-index:9999999999999}#spiderboprt a,#spiderboprt em{height:23px;line-height:23px;float:left;background:url(//l.bst.126.net/rsc/img/control/operatenew24.png?005) no-repeat}#spiderboprt a{padding:0 2px 0 0;cursor:pointer;text-decoration:none;background-position:right 0}#spiderboprt a:hover em,#spiderboprt em{color:#fff;padding:0 5px 0 26px;white-space:nowrap;font-weight:400;font-style:normal}#spiderboprt em{background-position:0 -750px;font-size:12px}#spiderboprt a:hover{background-position:right -870px}#spiderboprt a:hover em{background-position:0 -780px}";
css.innerHTML = cssText;
if (document.getElementById("spidercss") == undefined) {
document.getElementsByTagName("head")[0].appendChild(css);
}
if (document.getElementById("spiderboprt") == undefined) {
var Scope = document.getElementById("control_frame");
if (Scope) {
Scope.style.right = "77px";
var boprt = document.createElement("div");
boprt.id = "spiderboprt";
Scope.parentNode.insertBefore(boprt, Scope.nextSibling);
document.getElementById("spiderboprt").innerHTML = "下载";
}
}
var preg = /(.*?)\.(jpg|png|jpeg|gif)/i;
function getAllImages() {
var imgs = document.getElementsByClassName("imgclasstag");
var videos = document.getElementsByTagName("video");
return [
...Array.from(imgs).map(function (img) {
return img.getAttribute("bigimgsrc").match(preg)[0];
}),
...Array.from(videos).map(function (video) {
return video.src;
}),
];
}
function getFileExtensionFromUrl(url) {
// 移除查询参数(?后面的部分)
const cleanUrl = url.split("?")[0];
// 提取文件后缀名
const match = cleanUrl.match(/\.([a-zA-Z0-9]+)$/);
return match ? match[1] : ""; // 返回后缀名或空字符串
}
function saveFile(blob, filename) {
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
function downloadImages(urls) {
console.log(urls);
if (urls.length === 0) return;
const username = document.location.href.match(
/https:\/\/(.+?)\.lofter\.com/
)[1];
const postId = document.location.href.match(/post\/(.+)/)[1];
if (urls.length > 2) {
// 多于两张图片时打包下载
var jszip = new JSZip();
var promises = urls.map(function (url, index) {
return new Promise(function (resolve) {
GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "arraybuffer",
headers: {
"sec-fetch-site": "cross-site",
referer: document.location.href,
},
onload: function (xhr) {
const fileExt = getFileExtensionFromUrl(url);
jszip.file(
`${username} - ${document.title} - ${postId}${
index + 1
}.${fileExt}`,
xhr.response
);
resolve();
},
});
});
});
Promise.all(promises).then(function () {
jszip.generateAsync({ type: "blob" }).then(function (content) {
saveFile(content, `${username} - ${postId}.zip`);
});
});
} else {
// 两张以下直接下载
urls.forEach(function (url) {
const fileExt = getFileExtensionFromUrl(url);
const filename = `${username} - ${document.title} - ${postId}.${fileExt}`;
GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "blob",
headers: {
"sec-fetch-site": "cross-site",
referer: document.location.href,
},
onload: function (xhr) {
saveFile(xhr.response, filename);
},
});
});
}
}
// 添加点击事件处理
function addClickHandler() {
var downloadBtn = document.getElementById("spiderboprt");
if (downloadBtn) {
downloadBtn.onclick = function () {
var imageUrls = getAllImages();
downloadImages(imageUrls);
};
}
}
// 初始化
function init() {
// 如果按钮不存在,尝试创建
if (!document.getElementById("spiderboprt")) {
var controlFrame = document.getElementById("control_frame");
if (controlFrame) {
controlFrame.style.right = "77px";
var boprt = document.createElement("div");
boprt.id = "spiderboprt";
controlFrame.parentNode.insertBefore(boprt, controlFrame.nextSibling);
boprt.innerHTML = "下载";
}
}
// 添加点击事件
addClickHandler();
}
// 页面加载完成后初始化
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();