Instagram Gallery Downloader

Scans for images and downloads them from cache

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Instagram Gallery Downloader
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Scans for images and downloads them from cache
// @match        https://*.instagram.com/*
// @match        https://instagram.com/*
// @grant        GM_download
// @connect      instagram.com
// @connect      cdninstagram.com
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let targetUl = null;
    let foundImages = new Set();
    let scanInterval = null;
    let scanButton = null;
    let isScanning = false;
    let downloadInProgress = false;

    // Create and add floating button
    function createFloatingButton() {
        scanButton = document.createElement('button');
        updateButtonState();
        scanButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 9999;
            padding: 15px 20px;
            background-color: white;
            color: black;
            border: none;
            border-radius: 50px;
            cursor: pointer;
            min-width: 100px;
            transition: background-color 0.3s;
        `;

        scanButton.addEventListener('click', handleButtonClick);
        document.body.appendChild(scanButton);
    }

    // Handle button click based on current state
    function handleButtonClick() {
        if (isScanning) {
            stopScanning();
        } else if (downloadInProgress) {
            // Do nothing while downloading
            return;
        } else if (foundImages.size > 0) {
            startDownloading();
        } else {
            findLargestImageParentUl();
        }
    }

    // Update button appearance based on state
    function updateButtonState() {
        if (!scanButton) return;

        if (downloadInProgress) {
            scanButton.textContent = 'Downloading...';
        } else if (isScanning) {
            scanButton.textContent = 'Stop Scan';
        } else {
            scanButton.textContent = foundImages.size > 0 ? `Download ${foundImages.size} images` : 'Start scan';
        }
    }

    // Start downloading process
    async function startDownloading() {
        downloadInProgress = true;
        updateButtonState();

        const totalImages = foundImages.size;
        let currentImage = 0;

        for (const imageUrl of foundImages) {
            currentImage++;
            scanButton.textContent = `Downloading ${currentImage}/${totalImages}`;

            try {
                await downloadImageFromCache(imageUrl);
                await new Promise(resolve => setTimeout(resolve, 500)); // Delay between downloads
            } catch (error) {
                console.error('Error downloading image:', imageUrl, error);
            }
        }

        downloadInProgress = false;
        foundImages.clear();
        updateButtonState();
    }

    // Download single image from cache
    async function downloadImageFromCache(imageUrl) {
        return new Promise((resolve, reject) => {
            // First, try to fetch from cache
            fetch(imageUrl, { cache: 'force-cache' })
                .then(response => response.blob())
                .then(blob => {
                    // Create a download link
                    const filename = imageUrl.split('/').pop().split('?')[0] || 'image.jpg';
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                    resolve();
                })
                .catch(reject);
        });
    }

    // Find largest image and its parent UL
    function findLargestImageParentUl() {
        let maxArea = 0;
        let largestImg = null;

        const images = document.getElementsByTagName('img');

        for (const img of images) {
            const area = img.offsetWidth * img.offsetHeight;
            if (area > maxArea) {
                maxArea = area;
                largestImg = img;
            }
        }

        if (largestImg) {
            let element = largestImg;
            while (element && element.tagName !== 'UL') {
                element = element.parentElement;
            }

            if (element && element.tagName === 'UL') {
                targetUl = element;
                startScanning();
            } else {
                alert('No parent UL found for the largest image');
            }
        }
    }

    // Start periodic scanning
    function startScanning() {
        if (scanInterval) {
            clearInterval(scanInterval);
        }

        isScanning = true;
        updateButtonState();
        scanInterval = setInterval(scanForNewImages, 150);
    }

    // Stop scanning
    function stopScanning() {
        if (scanInterval) {
            clearInterval(scanInterval);
            scanInterval = null;
        }
        isScanning = false;
        updateButtonState();
        console.log('Scanning stopped. Total unique images found:', foundImages.size);
    }

    // Scan for new images in the target UL
    function scanForNewImages() {
        if (!targetUl) return;

        const images = targetUl.getElementsByTagName('img');
        for (const img of images) {
            const src = img.src;
            if (src && !foundImages.has(src)) {
                foundImages.add(src);
                console.log('New image found:', src);
            }
        }
    }

    // Initialize
    createFloatingButton();
})();