使用 Alt+左键 下载图片。已对 Instagram 优化。可通过 Tampermonkey 菜单设置下载子文件夹。
// ==UserScript==
// @name alt+左键保存图片 (可自定义文件夹)
// @namespace http://tampermonkey.net/
// @version 3.0
// @description 使用 Alt+左键 下载图片。已对 Instagram 优化。可通过 Tampermonkey 菜单设置下载子文件夹。
// @author yiha
// @match *://*/*
// @grant GM_download
// @grant GM_notification
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @connect *
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// --- 配置区域 ---
const STORAGE_KEY = 'customDownloadFolder'; // 用于存储文件夹名称的键
const DEFAULT_FOLDER = 'TM_Downloads'; // 默认的文件夹名称
// --- 注册菜单命令 ---
// 这会在 Tampermonkey 插件菜单中添加一个选项
GM_registerMenuCommand('设置下载子文件夹', () => {
const currentFolder = GM_getValue(STORAGE_KEY, DEFAULT_FOLDER);
const newFolder = prompt('请输入要保存到的下载子文件夹名称:', currentFolder);
// 如果用户输入了内容并且没有点“取消”
if (newFolder && newFolder.trim() !== '') {
GM_setValue(STORAGE_KEY, newFolder.trim());
GM_notification({
title: '设置已保存',
text: `下载文件夹已更新为: ${newFolder.trim()}`,
timeout: 3000
});
} else if (newFolder !== null) {
// 用户删除了所有内容并点击了确定,我们可以重置为默认值
GM_setValue(STORAGE_KEY, DEFAULT_FOLDER);
GM_notification({
title: '设置已重置',
text: `下载文件夹已重置为默认值: ${DEFAULT_FOLDER}`,
timeout: 3000
});
}
});
// --- 主要下载逻辑 ---
document.addEventListener('mousedown', function(e) {
if (!e.altKey || e.button !== 0) {
return;
}
e.preventDefault();
e.stopPropagation();
let imageUrl = '';
const clickedElement = e.target;
// 策略一:Instagram 专用逻辑
if (window.location.hostname.includes('instagram.com')) {
const article = clickedElement.closest('article');
if (article) {
const imgElement = article.querySelector('div._aagv img, li div._aagv img');
if (imgElement) {
const srcset = imgElement.srcset;
if (srcset) {
const sources = srcset.split(',').map(entry => {
const parts = entry.trim().split(/\s+/);
return { url: parts[0], width: parseInt(parts[1]?.replace('w', ''), 10) || 0 };
});
if (sources.length > 0) {
imageUrl = sources.reduce((max, current) => (current.width > max.width ? current : max)).url;
}
}
if (!imageUrl) {
imageUrl = imgElement.src;
}
}
}
}
// 策略二:通用逻辑
if (!imageUrl) {
let target = clickedElement;
if (target.tagName !== 'IMG') {
target = target.closest('div, a, figure')?.querySelector('img');
}
if (target && target.tagName === 'IMG') {
imageUrl = target.src || target.dataset.src;
}
}
if (!imageUrl) {
console.log('未能在此次点击中找到可下载的图片URL。');
return;
}
// --- 下载执行 ---
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
let fileExt = 'jpg';
try {
const urlPath = new URL(imageUrl).pathname;
const extensionMatch = urlPath.match(/\.([^.?]+)/);
if (extensionMatch && extensionMatch[1]) {
const potentialExt = extensionMatch[1].toLowerCase();
const validExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp'];
if (validExts.includes(potentialExt)) {
fileExt = potentialExt;
}
}
} catch (error) { console.error("解析URL时出错: ", error); }
const fileName = `image_${timestamp}.${fileExt}`;
// *** 关键改动:从存储中读取文件夹名称 ***
const downloadFolder = GM_getValue(STORAGE_KEY, DEFAULT_FOLDER);
const savePath = `${downloadFolder}/${fileName}`;
console.log(`准备下载到: ${savePath}`);
GM_download({
url: imageUrl,
name: savePath,
saveAs: false,
onload: function() {
console.log(`图片保存成功: ${savePath}`);
},
onerror: function(errorDetails) {
console.error('下载失败:', errorDetails);
GM_notification({
title: '图片保存失败',
text: `错误: ${errorDetails.error}`,
timeout: 5000
});
}
});
}, true);
})();