您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在B站个人空间的投稿 - 图文界面,提供右键直接下载动态中的图片,并记录已下载的动态ID,改变背景颜色来区别。(不支持旧版界面)
当前为
// ==UserScript== // @name Bilibili动态预览图片下载 // @namespace BilibiliDynamicPreviewDownload // @license MIT // @version 1.0.1 // @description 在B站个人空间的投稿 - 图文界面,提供右键直接下载动态中的图片,并记录已下载的动态ID,改变背景颜色来区别。(不支持旧版界面) // @author Kaesinol // @match https://space.bilibili.com/* // @grant GM_download // @grant GM_getValue // @grant GM_setValue // @require https://update.gf.qytechs.cn/scripts/473358/1237031/JSZip.js // ==/UserScript== (function () { "use strict"; // 获取已下载的动态ID集合(初始为空) let downloadedDynamicIds = GM_getValue("downloadedDynamicIds", {}); const fetchJsonData = async (dynamicId) => { const apiUrl = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${dynamicId}`; try { const response = await fetch(apiUrl); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const jsonData = await response.json(); const cardData = JSON.parse(jsonData.data.card.card); const pictures = cardData.item?.pictures?.map((p) => p.img_src.replace(/^http:/, "https:") ) || cardData.origin_image_urls || []; const uname = jsonData.data.card.desc.user_profile.info.uname; const uid = jsonData.data.card.desc.user_profile.info.uid; const fileName = `${uname} - ${uid} - ${dynamicId}`; console.log("提取的图片链接:", pictures); if (pictures.length > 1) await createZipAndDownload(pictures, fileName, dynamicId); else await downloadFile(pictures[0], 0, fileName); updateLinkColor(dynamicId); } catch (error) { console.error("请求或解析失败:", error); } }; const createZipAndDownload = async (urls, fileName, dynamicId) => { const zip = new JSZip(); const promises = urls.map((url, index) => { return fetch(url) .then((response) => { if (!response.ok) { throw new Error(`Failed to fetch ${url}`); } return response.blob(); }) .then((blob) => { const extensionMatch = getFileExtensionFromUrl(url); const extension = extensionMatch[1]; const fileNameWithIndex = `${fileName} - ${index + 1}.${extension}`; zip.file(fileNameWithIndex, blob); }) .catch((error) => { console.error("下载文件失败:", error); }); }); await Promise.all(promises); zip .generateAsync({ type: "blob" }) .then((content) => { GM_download({ url: URL.createObjectURL(content), name: `${fileName}.zip`, saveAs: false, }); // 记录已下载的动态ID并更新样式 downloadedDynamicIds[dynamicId] = true; GM_setValue("downloadedDynamicIds", downloadedDynamicIds); }) .catch((error) => { console.error("ZIP生成失败:", error); }); }; const getFileExtensionFromUrl = (url) => url.match(/\.([a-zA-Z0-9]+)$/); const downloadFile = async (url, index, fileName) => { try { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch ${url}`); } const blob = await response.blob(); const extensionMatch = getFileExtensionFromUrl(url); const extension = extensionMatch[1]; const fileDownloadName = `${fileName} - ${index + 1}.${extension}`; GM_download({ url: URL.createObjectURL(blob), name: fileDownloadName, saveAs: false, }); } catch (error) { console.error("下载文件失败:", error); } }; const handleEvent = (event, targetElement) => { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); if (event.type === "contextmenu") { const match = targetElement.querySelector("a").href.match(/\/(\d+)\??/); if (match && match[1]) { const dynamicId = match[1]; fetchJsonData(dynamicId); } else { console.warn("未匹配到动态ID:", targetElement.href); } } }; const updateLinkColor = (dynamicId) => { const link = document.querySelector(`a[href*="${dynamicId}"]`); if (link) { link.parentElement.style.backgroundColor = "green"; } }; const observer = new MutationObserver(() => { let targetElements = document.querySelectorAll( "div.opus-body div.item" ); targetElements.forEach((targetElement) => { if (!targetElement.hasAttribute("data-listener")) { targetElement.addEventListener( "contextmenu", (event) => handleEvent(event, targetElement), true ); targetElement.setAttribute("data-listener", "true"); } // 检查已下载的动态ID,并更新相应链接的颜色 const link = targetElement.querySelector("a"); const match = link.href.match(/\/(\d+)\??/); if (match && downloadedDynamicIds[match[1]]) { link.parentElement.style.backgroundColor = "green"; } }); }); observer.observe(document.body, { childList: true, subtree: true, }); const initialTargetElements = document.querySelectorAll( "div.opus-body div.item " ); initialTargetElements.forEach((targetElement) => { targetElement.addEventListener( "contextmenu", (event) => handleEvent(event, targetElement), true ); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址