您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
批量下载Lofter图片,修改重写自 兰陵笑笑生的Lofter原图查看下载
// ==UserScript== // @name Lofter(乐乎)原图下载 修改版 // @namespace LofterSpiderFix // @license 原作者保留 // @version 1.1.0 // @author Kaesinol // @author 兰陵笑笑生 // @homepage https://gist.github.com/kaixinol/3652d2484de12818e9b402808db30801 // @description 批量下载Lofter图片,修改重写自 兰陵笑笑生的Lofter原图查看下载 // @match https://*.lofter.com/post/* // @grant GM_xmlhttpRequest // @connect https://*.126.net // @connect https://*.lf1*.net // @require https://update.greasyfork.org/scripts/473358/1237031/JSZip.js // ==/UserScript== (() => { "use strict"; /** 注入样式 */ const injectStyle = () => { if (!document.getElementById("spidercss")) { const style = document.createElement("style"); style.id = "spidercss"; style.textContent = ` #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; } `; document.head.appendChild(style); } }; /** 创建下载按钮 */ const createButton = () => { if (!document.getElementById("spiderboprt")) { const scope = document.getElementById("control_frame"); if (scope) { scope.style.right = "77px"; const btn = document.createElement("div"); btn.id = "spiderboprt"; btn.innerHTML = `<a><em>下载</em></a>`; scope.parentNode.insertBefore(btn, scope.nextSibling); } } }; /** 获取所有图片和视频 */ const getAllMediaUrls = () => { const imgs = [...document.getElementsByClassName("imgclasstag")].map(img => img.getAttribute("bigimgsrc")?.match(/(.*?)\.(jpg|png|jpeg|gif)/i)?.[0] ).filter(Boolean); const videos = [...document.getElementsByTagName("video")].map(v => v.src); return [...imgs, ...videos]; }; /** 获取 URL 后缀名 */ const getFileExtension = (url) => { const cleanUrl = url.split("?")[0]; return cleanUrl.match(/\.([a-zA-Z0-9]+)$/)?.[1] ?? ""; }; /** 保存文件 */ const 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(); link.remove(); URL.revokeObjectURL(url); }; /** 使用 GM_xmlhttpRequest 下载并返回 blob/arraybuffer */ const fetchResource = (url, responseType = "blob") => new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url, responseType, headers: { "sec-fetch-site": "cross-site", referer: location.href, }, onload: (xhr) => resolve(xhr.response), onerror: reject, }); }); /** 下载逻辑 */ const downloadMedia = async (urls) => { if (!urls.length) return; const username = location.href.match(/https:\/\/(.+?)\.lofter\.com/)?.[1] ?? "user"; const postId = location.href.match(/post\/(.+)/)?.[1] ?? "post"; const safeTitle = document.title.replace(/[\\/:*?"<>|]/g, "_"); // 避免非法文件名 if (urls.length > 2) { // 多图打包 const zip = new JSZip(); await Promise.all(urls.map(async (url, index) => { const fileExt = getFileExtension(url); const data = await fetchResource(url, "arraybuffer"); zip.file(`${username} - ${safeTitle} - ${postId}_${index + 1}.${fileExt}`, data); })); const content = await zip.generateAsync({ type: "blob" }); saveFile(content, `${username} - ${postId}.zip`); } else { // 单/双图直接保存 for (const url of urls) { const fileExt = getFileExtension(url); const filename = `${username} - ${safeTitle} - ${postId}.${fileExt}`; const blob = await fetchResource(url, "blob"); saveFile(blob, filename); } } }; /** 按钮绑定事件 */ const bindClickHandler = () => { const btn = document.getElementById("spiderboprt"); if (btn) { btn.onclick = async () => { const urls = getAllMediaUrls(); await downloadMedia(urls); }; } }; /** 初始化 */ const init = () => { injectStyle(); createButton(); bindClickHandler(); }; document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", init) : init(); })();