alt+左键保存图片 (可自定义文件夹)

使用 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);
})();