您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
给花瓣的图加上“下载”按钮,方便下载
// ==UserScript== // @name 花瓣下载素材 - 星星专属 // @namespace http://tampermonkey.net/ // @version 0.1.1 // @description 给花瓣的图加上“下载”按钮,方便下载 // @author snow // @license MIT // @match *://huaban.com/* // @match *://hbimg.huabanimg.com/* // @grant GM_download // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @connect gd-hbimg.huaban.com // ==/UserScript== /* * * * 本脚本参考了潘志城_Neo的花瓣 - 添加下载按钮 相关实现思路,在此基础上修改,在此表示感谢。 * 特别感谢以下资源提供的灵感: * - Greasy Fork社区的相关用户脚本 * - 各类花瓣网辅助工具的开源实现 * * 本脚本为个人学习研究用途开发,仅用于提升用户体验, * 无意侵犯任何网站权益。如涉及侵权,请及时联系, * 我将立即删除相关代码。 * * 本脚本完全免费,仅供个人使用,禁止用于任何商业用途。 * 使用本脚本产生的一切后果由使用者自行承担。 */ (function () { "use strict"; // 所有图片 var allImages = []; // 按钮样式 var btnStyleText = "border:0; color:#ffffff ;background-color: rgb(26 179 125 / 75%);border-radius:8px;padding:3px 12px;cursor:pointer;pointer-events:all;"; var interval = null; var defaultSetting = { prefix: "HB", // 前缀 show_notification: true, // 是否显示通知消息 rename: false, // 是否重命名 show_source_img: true, // 是否显示大图 show_img_title: false, // 是否显示图片标题 download_type: "gm_download", // 下载方式 }; // 配置信息 var setting = GM_getValue("setting"); if (!setting) { setting = Object.assign({}, defaultSetting); } else { setting = Object.assign({}, defaultSetting, setting); } GM_setValue("setting", setting); // 主函数 function main() { document.body.addEventListener("click", function (e) { // 点击img标签的时候才尝试添加下载按钮 if ((e, e.target.tagName === "IMG")) { addDonwloadBtnToPreivew(); } }); // 网页滚动的时候,检测图片是否有添加下载按钮,没有就添加 document.addEventListener("scroll", throttle(addDownloadBtn, 300)); addDownloadBtn(); interval = setInterval(() => { if (allImages.length === 0) { addDownloadBtn(); } else { clearInterval(interval); } }, 1500); } main(); /** * 添加下载按钮(如果有按钮,就不添加) */ function addDownloadBtn() { if (document.URL.includes("pins")) { addDonwloadBtnToPreivew(); } else { if (!document.URL.includes("user")) { addDownloadBtnToDiscovery(); addDonwloadAllBtn(); } } } // 修改后的下载全部功能 function addDonwloadAllBtn() { // 创建下载按钮 var downloadBtn = document.createElement("button"); downloadBtn.innerText = "下载全部"; downloadBtn.style.cssText = btnStyleText + "position: fixed;" + "right: 20px;" + "top: 30%;" + "border-radius: 12px;" + "padding: 9px 12px;" + "z-index: 1000;" + "cursor: pointer;"; downloadBtn.className = "neo_add_btn"; // 添加点击事件 downloadBtn.addEventListener("click", function() { // 显示确认对话框 if (confirm("确定要下载本页所有图片吗?这可能需要一些时间。")) { downloadAllImages(); } }); // 添加到页面 document.body.appendChild(downloadBtn); } // 改进的下载所有图片函数 function downloadAllImages() { // 获取包含所有图片的外层容器 const container = document.querySelector( ".infinite-scroll-component__outerdiv" ); console.log(container,'////////////////////////////////////////////') if (!container) { console.error("未找到 infinite-scroll-component__outerdiv 元素"); return; } // 获取所有img元素 const images = container.querySelectorAll("img"); if (images.length === 0) { console.log("未找到任何图片"); return; } console.log(`找到 ${images.length} 张图片,开始下载...`); // 显示开始下载通知 show_notification({ text: `开始下载 ${images.length} 张图片`, title: "下载任务开始", timeout: 3000 }); // 遍历所有图片并下载 images.forEach((img, index) => { // 延迟执行,避免浏览器同时发起过多请求 setTimeout(() => { const pinInfo = img.parentNode.href.split("/"); const imgInfo = { title: img.getAttribute("alt") || `图片_${index + 1}`, src: img.getAttribute("src").replace("_fw240webp", ""), pin: pinInfo[pinInfo.length - 1] }; // 下载单张图片 downloadImage(imgInfo); // 显示进度通知 if ((index + 1) % 5 === 0 || index + 1 === images.length) { show_notification({ text: `已下载 ${index + 1}/${images.length} 张图片`, title: "下载进度", timeout: 2000 }); } }, index * 1000); // 每1秒下载一张,避免触发网站的防爬机制 }); } // 单张图片下载函数 function downloadImage(url, index) { console.log(`正在下载第 ${index} 张图片: ${url}`); // 创建一个隐藏的a标签用于下载 const a = document.createElement("a"); a.href = url; a.download = `image_${index}.jpg`; // 可以自定义文件名 a.style.display = "none"; document.body.appendChild(a); a.click(); document.body.removeChild(a); console.log(`第 ${index} 张图片下载完成`); } // 执行下载 function addDownloadBtnToDiscovery() { // Add loading indicator var loadingIndicator = document.createElement("div"); loadingIndicator.innerText = "脚本加载中..."; loadingIndicator.style.cssText = ` position: fixed; top: 200px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.7); color: white; padding: 15px 25px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 9999; font-size: 16px; display: flex; align-items: center; justify-content: center; `; document.body.appendChild(loadingIndicator); allImages = document.querySelectorAll(".transparent-img-bg.hb-image"); allImages.forEach((dom) => { var pinInfo = dom.parentNode.href.split("/"); // 图片标题和样式 var imgInfo = { title: dom.getAttribute("alt"), src: dom.getAttribute("src"), pin: pinInfo[pinInfo.length - 1], }; // 和包含图片的a标签同级的节点 var tempList = dom.parentNode.parentNode.childNodes; // 图片dom var imgNode = tempList[tempList.length - 1]; // 与图片父级a标签同级,并处于上方的元素 var lookNode = tempList[tempList.length - 2]; lookNode.setAttribute("hidden", true); lookNode.className = ""; lookNode.style.cssText = "position: absolute;bottom: 8px; right: 8px; display: flex; flex-direction: row;align-items: center;z-index:1"; // 添加鼠标悬停时的样式 lookNode.parentNode.addEventListener("mouseover", function () { lookNode.removeAttribute("hidden"); }); // 移除鼠标悬停时的样式 lookNode.parentNode.addEventListener("mouseout", function () { lookNode.setAttribute("hidden", true); }); if (lookNode.querySelectorAll(".neo_add").length === 0) { var btnContainer = document.createElement("div"); btnContainer.style = "display:flex;"; if (setting.show_source_img) { // 添加打开大图按钮 var sourceBtn = document.createElement("div"); sourceBtn.className = "neo_add_source"; sourceBtn.innerText = "大图"; sourceBtn.addEventListener("click", () => { window.open(imgInfo.src.replace("_fw240webp", "")); }); sourceBtn.style.cssText = btnStyleText + "margin-left:3px;"; btnContainer.appendChild(sourceBtn); } // 添加下载图片按钮 var downloadBtn = document.createElement("div"); downloadBtn.className = "neo_add"; downloadBtn.innerText = "下载"; downloadBtn.addEventListener("click", () => { downloadImage(imgInfo); }); downloadBtn.style.cssText = btnStyleText + "margin-left:3px;"; btnContainer.appendChild(downloadBtn); lookNode.insertBefore(btnContainer, null); // 添加图片标题 if (setting.show_img_title) { var domTitle = document.createElement("div"); domTitle.innerText = imgInfo.title; domTitle.title = imgInfo.title; domTitle.style.cssText = "padding-left:5px;text-overflow: ellipsis;white-space: nowrap;overflow: hidden; color: rgba(30,32,35,.65);height:3em;"; dom.parentNode.parentNode.parentNode.appendChild(domTitle); } } }); // Remove loading indicator when done setTimeout(() => { loadingIndicator.remove(); }, 1000); } function addDonwloadBtnToPreivew() { var newBtn = document.createElement("button"); newBtn.innerText = "画板"; newBtn.style.cssText = btnStyleText + "border-radius:12px;padding:9px 12px;margin-left:10px;"; newBtn.className = "neo_add_btn"; newBtn.addEventListener("click", function () { window.open("https://huaban.com/space", "_blank"); }); var downloadBtn = document.createElement("button"); downloadBtn.innerText = "下载"; downloadBtn.style.cssText = btnStyleText + "border-radius:12px;padding:9px 12px;margin-left:10px;"; downloadBtn.className = "neo_add_btn"; downloadBtn.addEventListener("click", function () { download(); }); function download() { var imgDom = document.querySelector("#pin_detail div img"); var pinInfo = document.URL.split("/"); var imgInfo = {}; imgInfo.title = imgDom.alt; imgInfo.src = imgDom.src; imgInfo.pin = pinInfo[pinInfo.length - 1]; downloadImage(imgInfo); } // 创建提示文字元素 var tipElement = document.createElement("div"); tipElement.innerHTML = "<span style='color:#f56c6c;font-size:12px;'>无水印素材可直接下载, ⚠️水印素材先点采集,再统一去画板里面下载</span>"; tipElement.style.cssText = "position:absolute;right:0;top:-23px;background:linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);padding:10px 8px;border-radius:12px;"; var count = 0; var maxCount = 8; var interval = setInterval(function () { var btnDom = document.querySelector("#pin_detail div button"); if (btnDom) { clearInterval(interval); var neoAddDom = document.querySelector( "#pin_detail div button.neo_add_btn" ); if (neoAddDom) return; // 确保pin_detail有relative定位 var pinDetail = document.querySelector("#pin_detail"); if (pinDetail) { pinDetail.style.position = "relative"; // 添加按钮和提示 btnDom.parentNode.appendChild(downloadBtn); btnDom.parentNode.appendChild(newBtn); pinDetail.appendChild(tipElement); } } if (count >= maxCount) { clearInterval(interval); } else { count++; } }, 1000); } /** * 下载图片 * @param {Object} imgInfo src:图片链接; title:图片标题 */ function sanitizeFilename(name) { return name.replace(/[\\/:*?"<>|]/g, "_"); } function downloadImage(imgInfo) { const extension = getExtensionFromUrl(imgInfo.src); let imgTitle = imgInfo.title ? sanitizeFilename(imgInfo.title) : "无标题"; if (setting.rename) { imgTitle = (setting.prefix ? setting.prefix + "-" : "") + formatDate(new Date()) + "-" + imgInfo.pin; } imgInfo.src = imgInfo.src.replace(/(_fw\d+.*|_sq\d+.*)/, ""); show_notification({ text: imgTitle, title: "图片已添加下载", timeout: 2000, }); switch (setting.download_type) { case "gm_download": imageDownload_with_gm_download(imgInfo.src, imgTitle, extension); break; case "fetch": imageDownload_with_fetch(imgInfo.src, imgTitle, extension); break; case "xhr": imageDownload_with_Xhr_download(imgInfo.src, imgTitle, extension); break; case "xmlhttpRequest": imageDownload_with_xmlhttpRequest_download(imgInfo.src, imgTitle); break; default: imageDownload_with_Xhr_download(imgInfo.src, imgTitle, extension); break; } } function show_notification(item) { if (setting.show_notification) { GM_notification(item); } } function throttle(cb, wait = 300) { var last = 0; return function () { var now = new Date().getTime(); if (now - last > wait) { cb.call(this); last = new Date().getTime(); } }; } //格式化时间 function formatDate(dat) { //获取年月日,时间 var year = dat.getFullYear(); var mon = dat.getMonth() + 1 < 10 ? "0" + (dat.getMonth() + 1) : dat.getMonth() + 1; var data = dat.getDate() < 10 ? "0" + dat.getDate() : dat.getDate(); var newDate = year + mon + data; return newDate; } /** * 用fecth下载图片 */ function imageDownload_with_fetch(src, title) { const extension = getExtensionFromUrl(src); fetch(src) .then((response) => response.blob()) .then((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = title + extension; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); document.body.removeChild(a); }) .catch((error) => { show_notification({ text: title + "\n" + error, title: "下载出错", timeout: 5000, }); console.error(error); }); } function getExtensionFromUrl(url) { const match = url.match(/\.(jpeg|jpg|png|gif|webp|bmp)/); return match ? "." + match[1] : ".png"; // 默认使用.jpg } /** * 用GM_download 下载图片 */ function imageDownload_with_gm_download(src, title) { const extension = getExtensionFromUrl(src); GM_download({ url: src, name: title + extension, onload: function () { show_notification({ text: title, title: "图片已完成下载", timeout: 5000, }); }, onerror: function (error) { show_notification({ text: title + "\n" + src, title: "下载出错", timeout: 5000, }); console.error(error); }, }); } })();