您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在B站个人空间的投稿 - 图文界面,提供右键直接下载动态中的图片
当前为
// ==UserScript== // @name Bilibili动态预览图片下载 // @namespace http://tampermonkey.net/ // @version 0.8 // @description 在B站个人空间的投稿 - 图文界面,提供右键直接下载动态中的图片 // @author You // @match https://space.bilibili.com/*/upload/opus // @grant none // @require https://update.gf.qytechs.cn/scripts/473358/1237031/JSZip.js // ==/UserScript== (function() { 'use strict'; 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:')) || []; 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); downloadFiles(pictures, fileName); } catch (error) { console.error('请求或解析失败:', error); } }; const downloadFiles = async (urls, fileName) => { if (urls.length > 1) { await createZipAndDownload(urls, fileName); } else { const promises = urls.map((url, index) => downloadFile(url, index, fileName)); await Promise.all(promises); } }; const createZipAndDownload = async (urls, fileName) => { 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 => { // Get the file extension dynamically using the lambda const extensionMatch = getFileExtensionFromUrl(url); const extension = extensionMatch[1]; // No error handling, must have an extension const fileNameWithIndex = `${fileName} - ${index + 1}.${extension}`; zip.file(fileNameWithIndex, blob); }) .catch(error => { console.error('下载文件失败:', error); }); }); await Promise.all(promises); // Generate and download the ZIP file zip.generateAsync({ type: 'blob' }) .then(content => { const link = document.createElement('a'); link.href = URL.createObjectURL(content); link.download = `${fileName}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); }) .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]; // No error handling, must have an extension const fileDownloadName = `${fileName} - ${index + 1}.${extension}`; const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = fileDownloadName; document.body.appendChild(link); link.click(); document.body.removeChild(link); } catch (error) { console.error('下载文件失败:', error); } }; // Lambda function to get file extension const handleEvent = (event, targetElement) => { event.preventDefault(); event.stopPropagation(); // 阻止事件冒泡 event.stopImmediatePropagation(); // 更强力阻止 if (event.type === 'contextmenu') { // 右键事件 const match = targetElement.href.match(/\/(\d+)\??/); if (match && match[1]) { const dynamicId = match[1]; fetchJsonData(dynamicId); } else { console.warn('未匹配到动态ID:', targetElement.href); } } }; const observer = new MutationObserver(() => { const targetElements = document.querySelectorAll('div.opus-body > div > div > div > div > div > div a'); targetElements.forEach(targetElement => { if (!targetElement.hasAttribute('data-listener')) { targetElement.addEventListener('contextmenu', (event) => handleEvent(event, targetElement), true); // 捕获阶段绑定 targetElement.setAttribute('data-listener', 'true'); // 防止重复绑定 } }); }); // 配置 MutationObserver observer.observe(document.body, { childList: true, subtree: true }); // 初次匹配页面上已经存在的元素 const initialTargetElements = document.querySelectorAll('div.opus-body > div > div > div > div > div > div a'); initialTargetElements.forEach(targetElement => { targetElement.addEventListener('contextmenu', (event) => handleEvent(event, targetElement), true); // 捕获阶段绑定 }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址