批量图片提取与下载

提取图片后支持全选、取消全选、一键下载全部图片和下载选中图片为 ZIP 文件,UI 美化版,带链接输入界面。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         批量图片提取与下载
// @namespace    http://tampermonkey.net/
// @version      1.5.3
// @description  提取图片后支持全选、取消全选、一键下载全部图片和下载选中图片为 ZIP 文件,UI 美化版,带链接输入界面。
// @author       vicwang
// @match        *://*/*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    // 创建按钮容器
    const buttonContainer = document.createElement('div');
    buttonContainer.style.position = 'fixed';
    buttonContainer.style.top = '0';
    buttonContainer.style.left = '50%';
    buttonContainer.style.transform = 'translateX(-50%)';
    buttonContainer.style.zIndex = '9999';
    buttonContainer.style.display = 'flex';
    buttonContainer.style.gap = '10px';
    buttonContainer.style.padding = '10px';
    buttonContainer.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
    buttonContainer.style.borderRadius = '0 0 10px 10px';
    buttonContainer.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
    buttonContainer.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
    buttonContainer.style.opacity = '0';
    buttonContainer.style.transform = 'translateY(-100%)';
    document.body.appendChild(buttonContainer);

    // 创建“开始”按钮
    const startButton = document.createElement('button');
    startButton.textContent = '输入图片链接';
    startButton.style.padding = '8px 16px';
    startButton.style.backgroundColor = '#007BFF';
    startButton.style.color = '#fff';
    startButton.style.border = 'none';
    startButton.style.borderRadius = '5px';
    startButton.style.cursor = 'pointer';
    startButton.style.fontSize = '14px';
    startButton.style.fontWeight = '500';
    startButton.style.transition = 'background-color 0.3s ease';
    buttonContainer.appendChild(startButton);

    // 创建“提取”按钮
    const extractButton = document.createElement('button');
    extractButton.textContent = '提取网页图片';
    extractButton.style.padding = '8px 16px';
    extractButton.style.backgroundColor = '#28A745';
    extractButton.style.color = '#fff';
    extractButton.style.border = 'none';
    extractButton.style.borderRadius = '5px';
    extractButton.style.cursor = 'pointer';
    extractButton.style.fontSize = '14px';
    extractButton.style.fontWeight = '500';
    extractButton.style.transition = 'background-color 0.3s ease';
    buttonContainer.appendChild(extractButton);

    // 按钮悬停效果
    const setHoverEffect = (button, hoverColor) => {
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = hoverColor;
        });
        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = button === startButton ? '#007BFF' : '#28A745';
        });
    };

    setHoverEffect(startButton, '#0056b3');
    setHoverEffect(extractButton, '#218838');

    // 鼠标移动到网页顶部时显示按钮
    const showButtons = () => {
        buttonContainer.style.opacity = '1';
        buttonContainer.style.transform = 'translateY(0)';
    };

    // 鼠标离开网页顶部时隐藏按钮
    const hideButtons = () => {
        buttonContainer.style.opacity = '0';
        buttonContainer.style.transform = 'translateY(-100%)';
    };

    // 监听鼠标移动
    document.addEventListener('mousemove', (e) => {
        if (e.clientY <= 50) { // 鼠标靠近顶部 50px 时显示按钮
            showButtons();
        } else {
            hideButtons();
        }
    });

    // 点击“开始”按钮
    startButton.addEventListener('click', () => {
        // 创建模态对话框
        const modal = document.createElement('div');
        modal.style.position = 'fixed';
        modal.style.top = '0';
        modal.style.left = '0';
        modal.style.width = '100%';
        modal.style.height = '100%';
        modal.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        modal.style.zIndex = '10000';
        modal.style.display = 'flex';
        modal.style.justifyContent = 'center';
        modal.style.alignItems = 'center';
        document.body.appendChild(modal);

        // 创建对话框内容
        const dialog = document.createElement('div');
        dialog.style.backgroundColor = '#fff';
        dialog.style.padding = '20px';
        dialog.style.borderRadius = '10px';
        dialog.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.2)';
        dialog.style.width = '400px';
        dialog.style.maxWidth = '90%';
        modal.appendChild(dialog);

        // 创建标题
        const title = document.createElement('h3');
        title.textContent = '请输入图片链接';
        title.style.marginTop = '0';
        title.style.fontSize = '18px';
        title.style.color = '#333';
        dialog.appendChild(title);

        // 创建输入框
        const inputBox = document.createElement('textarea');
        inputBox.placeholder = '每行一个链接';
        inputBox.style.width = '100%';
        inputBox.style.height = '150px';
        inputBox.style.padding = '10px';
        inputBox.style.border = '1px solid #ccc';
        inputBox.style.borderRadius = '5px';
        inputBox.style.fontSize = '14px';
        inputBox.style.marginBottom = '15px';
        inputBox.style.boxSizing = 'border-box';
        dialog.appendChild(inputBox);

        // 创建按钮容器
        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'flex-end';
        buttonContainer.style.gap = '10px';
        dialog.appendChild(buttonContainer);

        // 创建确认按钮
        const confirmButton = document.createElement('button');
        confirmButton.textContent = '确认';
        confirmButton.style.padding = '8px 16px';
        confirmButton.style.backgroundColor = '#28A745';
        confirmButton.style.color = '#fff';
        confirmButton.style.border = 'none';
        confirmButton.style.borderRadius = '5px';
        confirmButton.style.cursor = 'pointer';
        confirmButton.style.fontSize = '14px';
        confirmButton.style.transition = 'background-color 0.3s ease';
        buttonContainer.appendChild(confirmButton);

        // 确认按钮悬停效果
        setHoverEffect(confirmButton, '#218838');

        // 创建取消按钮
        const cancelButton = document.createElement('button');
        cancelButton.textContent = '取消';
        cancelButton.style.padding = '8px 16px';
        cancelButton.style.backgroundColor = '#FF4C4C';
        cancelButton.style.color = '#fff';
        cancelButton.style.border = 'none';
        cancelButton.style.borderRadius = '5px';
        cancelButton.style.cursor = 'pointer';
        cancelButton.style.fontSize = '14px';
        cancelButton.style.transition = 'background-color 0.3s ease';
        buttonContainer.appendChild(cancelButton);

        // 取消按钮悬停效果
        setHoverEffect(cancelButton, '#cc0000');

        // 确认按钮点击事件
        confirmButton.addEventListener('click', () => {
            const links = inputBox.value.split('\n').map(link => link.trim()).filter(link => link);
            if (links.length === 0) {
                alert('请输入至少一个有效链接');
                return;
            }
            modal.remove(); // 关闭对话框
            processLinks(links); // 处理链接
        });

        // 取消按钮点击事件
        cancelButton.addEventListener('click', () => {
            modal.remove(); // 关闭对话框
        });
    });

    // 点击“提取”按钮
    extractButton.addEventListener('click', () => {
        // 提取当前网页中的所有图片
        const images = Array.from(document.querySelectorAll('img')).map(img => img.src);
        if (images.length === 0) {
            alert('当前网页未找到图片');
            return;
        }
        processLinks(images); // 处理图片链接
    });

    // 处理链接
    function processLinks(links) {
        // 创建图片展示容器
        const container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.top = '0';
        container.style.left = '0';
        container.style.width = '100%';
        container.style.height = '100%';
        container.style.backgroundColor = 'rgba(0, 0, 0, 0.95)';
        container.style.overflowY = 'scroll';
        container.style.zIndex = '10000';
        container.style.display = 'flex';
        container.style.flexWrap = 'wrap';
        container.style.gap = '15px';
        container.style.padding = '20px';
        container.style.boxSizing = 'border-box';
        document.body.appendChild(container);

        // 创建关闭按钮
        const closeButton = document.createElement('button');
        closeButton.textContent = '关闭';
        closeButton.style.position = 'fixed';
        closeButton.style.top = '20px';
        closeButton.style.right = '20px';
        closeButton.style.zIndex = '10001';
        closeButton.style.padding = '10px 20px';
        closeButton.style.backgroundColor = '#FF4C4C';
        closeButton.style.color = '#fff';
        closeButton.style.border = 'none';
        closeButton.style.borderRadius = '8px';
        closeButton.style.cursor = 'pointer';
        closeButton.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
        closeButton.style.fontSize = '14px';
        closeButton.style.fontWeight = '500';
        closeButton.style.transition = 'background-color 0.3s ease';
        container.appendChild(closeButton);

        // 关闭按钮悬停效果
        setHoverEffect(closeButton, '#cc0000');

        closeButton.addEventListener('click', () => {
            container.remove();
        });

        // 图片列表
        const imageList = links;
        const selectedImages = new Set(); // 记录选中的图片

        // 显示所有图片
        const imageElements = [];
        imageList.forEach((src, index) => {
            const imgWrapper = document.createElement('div');
            imgWrapper.style.flex = '1 1 calc(25% - 15px)';
            imgWrapper.style.display = 'flex';
            imgWrapper.style.alignItems = 'center';
            imgWrapper.style.justifyContent = 'center';
            imgWrapper.style.backgroundColor = '#fff';
            imgWrapper.style.borderRadius = '8px';
            imgWrapper.style.overflow = 'hidden';
            imgWrapper.style.position = 'relative';
            imgWrapper.style.cursor = 'pointer';
            imgWrapper.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease';

            // 图片悬停效果
            imgWrapper.addEventListener('mouseenter', () => {
                imgWrapper.style.transform = 'scale(1.02)';
                imgWrapper.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.2)';
            });
            imgWrapper.addEventListener('mouseleave', () => {
                imgWrapper.style.transform = 'scale(1)';
                imgWrapper.style.boxShadow = 'none';
            });

            const img = document.createElement('img');
            img.src = src;
            img.style.width = '100%';
            img.style.height = 'auto';
            img.style.borderRadius = '8px';
            img.alt = '图片';

            // 选中效果
            const overlay = document.createElement('div');
            overlay.style.position = 'absolute';
            overlay.style.top = '0';
            overlay.style.left = '0';
            overlay.style.width = '100%';
            overlay.style.height = '100%';
            overlay.style.backgroundColor = 'rgba(0, 123, 255, 0.5)';
            overlay.style.display = 'none';
            overlay.style.borderRadius = '8px';
            imgWrapper.appendChild(overlay);

            imgWrapper.appendChild(img);
            container.appendChild(imgWrapper);
            imageElements.push({ src, wrapper: imgWrapper, overlay });

            // 点击图片进行选中/取消
            imgWrapper.addEventListener('click', () => {
                if (selectedImages.has(src)) {
                    selectedImages.delete(src);
                    overlay.style.display = 'none';
                } else {
                    selectedImages.add(src);
                    overlay.style.display = 'block';
                }
            });
        });

        // 全选按钮
        const selectAllButton = document.createElement('button');
        selectAllButton.textContent = '全选';
        selectAllButton.style.position = 'fixed';
        selectAllButton.style.bottom = '100px';
        selectAllButton.style.right = '20px';
        selectAllButton.style.zIndex = '10001';
        selectAllButton.style.padding = '10px 20px';
        selectAllButton.style.backgroundColor = '#007BFF';
        selectAllButton.style.color = '#fff';
        selectAllButton.style.border = 'none';
        selectAllButton.style.borderRadius = '8px';
        selectAllButton.style.cursor = 'pointer';
        selectAllButton.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
        selectAllButton.style.fontSize = '14px';
        selectAllButton.style.fontWeight = '500';
        selectAllButton.style.transition = 'background-color 0.3s ease';
        container.appendChild(selectAllButton);

        // 全选按钮悬停效果
        setHoverEffect(selectAllButton, '#0056b3');

        selectAllButton.addEventListener('click', () => {
            imageElements.forEach(({ src, overlay }) => {
                selectedImages.add(src);
                overlay.style.display = 'block';
            });
        });

        // 取消全选按钮
        const deselectAllButton = document.createElement('button');
        deselectAllButton.textContent = '取消全选';
        deselectAllButton.style.position = 'fixed';
        deselectAllButton.style.bottom = '60px';
        deselectAllButton.style.right = '20px';
        deselectAllButton.style.zIndex = '10001';
        deselectAllButton.style.padding = '10px 20px';
        deselectAllButton.style.backgroundColor = '#FF5722';
        deselectAllButton.style.color = '#fff';
        deselectAllButton.style.border = 'none';
        deselectAllButton.style.borderRadius = '8px';
        deselectAllButton.style.cursor = 'pointer';
        deselectAllButton.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
        deselectAllButton.style.fontSize = '14px';
        deselectAllButton.style.fontWeight = '500';
        deselectAllButton.style.transition = 'background-color 0.3s ease';
        container.appendChild(deselectAllButton);

        // 取消全选按钮悬停效果
        setHoverEffect(deselectAllButton, '#e64a19');

        deselectAllButton.addEventListener('click', () => {
            imageElements.forEach(({ src, overlay }) => {
                selectedImages.delete(src);
                overlay.style.display = 'none';
            });
        });

        // 下载选中图片按钮
        const downloadSelectedButton = document.createElement('button');
        downloadSelectedButton.textContent = '下载选中图片(ZIP)';
        downloadSelectedButton.style.position = 'fixed';
        downloadSelectedButton.style.bottom = '20px';
        downloadSelectedButton.style.right = '20px';
        downloadSelectedButton.style.zIndex = '10001';
        downloadSelectedButton.style.padding = '10px 20px';
        downloadSelectedButton.style.backgroundColor = '#28A745';
        downloadSelectedButton.style.color = '#fff';
        downloadSelectedButton.style.border = 'none';
        downloadSelectedButton.style.borderRadius = '8px';
        downloadSelectedButton.style.cursor = 'pointer';
        downloadSelectedButton.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
        downloadSelectedButton.style.fontSize = '14px';
        downloadSelectedButton.style.fontWeight = '500';
        downloadSelectedButton.style.transition = 'background-color 0.3s ease';
        container.appendChild(downloadSelectedButton);

        // 下载按钮悬停效果
        setHoverEffect(downloadSelectedButton, '#218838');

        downloadSelectedButton.addEventListener('click', async () => {
            if (selectedImages.size === 0) {
                alert('请先选择图片!');
                return;
            }

            const zip = new JSZip();
            const selectedArray = Array.from(selectedImages);

            for (let i = 0; i < selectedArray.length; i++) {
                const src = selectedArray[i];
                const filename = `image_${i + 1}.${src.split('.').pop().split('?')[0]}`;
                const response = await fetch(src);
                const blob = await response.blob();
                zip.file(filename, blob);
            }

            const content = await zip.generateAsync({ type: 'blob' });
            const link = document.createElement('a');
            link.href = URL.createObjectURL(content);
            link.download = 'selected_images.zip';
            link.click();
        });
    }
})();