Greasy Fork is available in English.
为即梦添加按钮,可以直接下载无水印原图
// ==UserScript==
// @name 即梦下载无水印原图
// @namespace http://tampermonkey.net/
// @version 3.1
// @description 为即梦添加按钮,可以直接下载无水印原图
// @author psdoc烛光
// @match https://jimeng.jianying.com/*
// @icon https://favicon.im/jimeng.jianying.com?larger=true&t=1755764200795
// @grant GM_download
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 核心配置
const CONFIG = {
maxRetry: 3,
retryDelay: 500,
debounceTime: 1000,
selectors: [
'div.operation-area-uoDdSN',
'div.action-buttons-wrapper-ibCKz2',
'div.operation-buttons-ita9Ow'
]
};
// 状态管理
let state = {
isAdding: false,
lastAddTime: 0,
retryCount: 0,
observer: null
};
/**
* 查找目标图片
*/
function findTargetImage() {
const selectors = [
'img[crossorigin="anonymous"]:not([src*="avatar"]):not([src*="profile"])',
'img[src*="jimeng"]:not([src*="avatar"]):not([src*="profile"])',
'img[src*="byteimg"]:not([src*="avatar"]):not([src*="profile"])',
'img[src*=".jpg"]:not([src*="avatar"]):not([src*="profile"])',
'img[src*=".png"]:not([src*="avatar"]):not([src*="profile"])'
];
const images = [];
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(img => {
if (img.src && img.src.includes('http')) {
const area = (img.naturalWidth || img.width) * (img.naturalHeight || img.height);
if (area > 10000) {
images.push({ element: img, src: img.src, area });
}
}
});
});
return images.sort((a, b) => b.area - a.area)[0];
}
/**
* 下载图片
*/
function downloadImage() {
const target = findTargetImage();
if (!target) {
console.log('未找到可下载的图片');
return;
}
const url = target.src;
const filename = url.split('/').pop().split('?')[0] || 'image.jpg';
GM_download({
url,
name: filename,
saveAs: true,
onload: () => console.log('下载成功'),
onerror: (error) => {
console.log('GM_download失败,尝试降级方案');
fallbackDownload(url, filename);
}
});
}
/**
* 降级下载方案
*/
function fallbackDownload(url, filename) {
try {
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
} catch (error) {
window.open(url, '_blank');
}
}
/**
* 创建下载按钮
*/
function createButton() {
const button = document.createElement('div');
button.className = 'operation-button-PU0Wce jimeng-download-btn';
button.innerHTML = `
<svg width="1em" height="1em" viewBox="0 0 24 24" fill="none">
<path d="M12 2a1 1 0 0 1 1 1v10.312l4.023-4.021a1 1 0 0 1 1.414 1.414l-5.73 5.728a1 1 0 0 1-1.414 0l-5.73-5.728A1 1 0 1 1 6.977 9.29L11 13.312V3a1 1 0 0 1 1-1ZM3 20.002a1 1 0 0 1 1-1L20 19a1 1 0 0 1 0 2l-16 .002a1 1 0 0 1-1-1Z" fill="currentColor"/>
</svg>
<span>下载原图</span>
`;
button.style.cssText = `
display: inline-flex;
align-items: center;
gap: 4px;
padding: 8px 12px;
background: #1890ff;
color: white;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
margin: 4px;
transition: all 0.3s;
`;
button.addEventListener('mouseenter', () => button.style.background = '#40a9ff');
button.addEventListener('mouseleave', () => button.style.background = '#1890ff');
button.addEventListener('click', downloadImage);
return button;
}
/**
* 查找并添加按钮到容器
*/
function addButtons() {
if (state.isAdding || Date.now() - state.lastAddTime < CONFIG.debounceTime) {
return false;
}
// 检查是否已经有按钮存在
if (document.querySelector('.jimeng-download-btn')) {
return false;
}
state.isAdding = true;
let added = 0;
try {
// 按优先级添加:先尝试在操作按钮组添加,再尝试其他位置
const prioritySelectors = [
'div.operation-buttons-ita9Ow', // 操作按钮组(优先级最高)
'div.action-buttons-wrapper-ibCKz2', // 动作按钮包装器
'div.operation-area-uoDdSN' // 操作区域
];
for (const selector of prioritySelectors) {
const containers = document.querySelectorAll(selector);
for (const container of containers) {
if (!container.querySelector('.jimeng-download-btn')) {
const button = createButton();
// 根据容器类型调整样式
if (selector.includes('operation-buttons')) {
button.style.margin = '0';
button.style.padding = '8px';
button.style.minWidth = 'auto';
}
container.appendChild(button);
added++;
// 只添加一个按钮,避免重复
return true;
}
}
}
} finally {
state.isAdding = false;
state.lastAddTime = Date.now();
}
return added > 0;
}
/**
* 删除所有按钮
*/
function removeButtons() {
document.querySelectorAll('.jimeng-download-btn').forEach(btn => btn.remove());
}
/**
* 初始化
*/
function init() {
if (document.querySelector('.jimeng-download-btn')) return;
if (!addButtons() && state.retryCount < CONFIG.maxRetry) {
state.retryCount++;
setTimeout(init, CONFIG.retryDelay * state.retryCount);
}
}
/**
* 设置观察者
*/
function setupObserver() {
state.observer = new MutationObserver(() => {
// 检查是否已经有按钮存在
if (document.querySelector('.jimeng-download-btn')) {
return;
}
// 检查是否有合适的容器但没有按钮
const hasEmptyContainers = CONFIG.selectors.some(selector =>
Array.from(document.querySelectorAll(selector))
.some(container => !container.querySelector('.jimeng-download-btn'))
);
if (hasEmptyContainers) {
setTimeout(addButtons, 100);
}
});
state.observer.observe(document.body, {
childList: true,
subtree: true
});
}
/**
* 设置快捷键
*/
function setupShortcuts() {
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey) {
if (e.key === 'D') {
e.preventDefault();
removeButtons();
} else if (e.key === 'A') {
e.preventDefault();
addButtons();
}
}
});
}
// 启动脚本
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
init();
setupObserver();
setupShortcuts();
});
} else {
init();
setupObserver();
setupShortcuts();
}
})();