// ==UserScript== // @name 从豆包下载无水印图片 Download Origin Image from Doubao without Watermark // @name:en Download Origin Image from Doubao without Watermark 从豆包下载无水印图片 // @namespace https://github.com/catscarlet/Download-Origin-Image-from-Doubao-without-Watermark // @description 从豆包(www.doubao.com)下载无水印图片 Download Origin Image from www.doubao.com without Watermark. // @description:en Download Origin Image from www.doubao.com without Watermark. 从豆包(www.doubao.com)下载无水印图片 // @version 0.5.0 // @author catscarlet // @license GNU Affero General Public License v3.0 // @match https://www.doubao.com/chat/* // @run-at document-end // @grant none // ==/UserScript== const removeDefaultDownloadButton = 1; //Hide Original Download Button by default. If you want the default Download Button appear as usual, set this value to 0. (function() { 'use strict'; let throttleTimer; let debounceTimer; const observer = new MutationObserver((mutationsList) => { const now = Date.now(); if (!throttleTimer || now - throttleTimer > 300) { throttleTimer = now; clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { if (removeDefaultDownloadButton) { const EditImageDownloadButtons = document.querySelectorAll('div[data-testid="edit_image_download_button"]'); EditImageDownloadButtons.forEach((EditImageDownloadButton) => { if (EditImageDownloadButton && EditImageDownloadButton.style.display != 'none') { EditImageDownloadButton.style.display = 'none'; } }); } const images = document.querySelectorAll('img.preview-img-fe4pbK.img-bg-l0S60q'); if (images.length == 0) { return false; } images.forEach((image) => { if (!image.parentNode.querySelector('.imagelink-nowatermark')) { const link = document.createElement('a'); link.textContent = '点击下载无水印图片'; link.style.whiteSpace = 'break-spaces'; link.classList.add('imagelink-nowatermark'); link.style.position = 'absolute'; link.style.backgroundColor = '#007BFF'; link.style.color = 'white'; link.style.padding = '10px 20px'; link.style.border = 'none'; link.style.borderRadius = '5px'; link.style.zIndex = 1; link.style.textDecoration = 'none'; link.style.opacity = '0.8'; const x = 0; const y = 0; link.style.left = x + 'px'; link.style.top = y + 'px'; link.addEventListener('mouseover', function() { this.style.backgroundColor = '#0056b3'; this.style.cursor = 'pointer'; }); link.addEventListener('mouseout', function() { this.style.backgroundColor = '#007BFF'; this.style.cursor = ''; }); link.addEventListener('click', async () => { getCrossOriginImage(link); }); image.parentNode.appendChild(link); } else { //console.log('added, skip.'); } }); } } }, 300); } }); const config = { childList: true, attributes: false, subtree: true, }; observer.observe(document.documentElement, config); })(); async function getCrossOriginImage(link) { const currentTitle = document.title.replace('- 豆包', '').trim(); const chatID = document.location.pathname.replace('/chat/', '').trim(); const timeStr = getYmdHMS(); const imageUrl = link.parentNode.querySelector('img').src; const imageName = currentTitle + '-' + chatID + '-' + timeStr + '.png'; try { const response = await fetch(imageUrl, {mode: 'cors'}); const blob = await response.blob(); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = imageName; a.style.display = 'none'; document.body.appendChild(a); setTimeout(() => { a.click(); }, 10); setTimeout(() => { URL.revokeObjectURL(url); document.body.removeChild(a); }, 1000); } catch (error) { console.error('图片加载失败,请确保图片服务器开启了 CORS 支持。'); alert('图片加载失败,请确保图片服务器开启了 CORS 支持。'); } } function getYmdHMS() { const date = new Date(); const Y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); const H = String(date.getHours()).padStart(2, '0'); const M = String(date.getMinutes()).padStart(2, '0'); const S = String(date.getSeconds()).padStart(2, '0'); const result = `${Y}${m}${d}${H}${M}${S}`; return result; }