ImageSnatcher

Descarga imágenes rápidamente pasando el cursor sobre ellas y presionando la tecla S.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         ImageSnatcher
// @name:es      ImageSnatcher
// @version      1.2.4
// @description  Quickly download images by hovering over them and pressing the S key.
// @description:es Descarga imágenes rápidamente pasando el cursor sobre ellas y presionando la tecla S.
// @author       Adam Jensen
// @match        *://*/*
// @grant        GM_download
// @license      MIT
// @namespace https://greasyfork.org/en/scripts/518034-imagesnatcher
// ==/UserScript==

(function () {
    'use strict';

    const validExtensions = /\.(jpe?g|png|gif|webp|bmp|svg|ico|tiff?|avif|jxl|heic|heif|dds|apng|pjpeg|pjpg|webm)$/i;
    const preprocessedImages = []; // Array to store the last 10 preprocessed images
    const maxHistory = 10; // Maximum number of images to keep in the history
    const downloadQueue = []; // Queue of images to be downloaded
    let isDownloading = false; // Flag to track the download state
    let lastHoveredImage = null; // Variable to store the last hovered image details

    let lastProcessedUrl = null; 
    function preprocessImage(target) {
        if (!target) return;

        let imageUrl;
        let imageTitle = '';
        let potentialBetterUrl = null;

        const parentAnchor = target.closest('a');
        if (parentAnchor && parentAnchor.href && validExtensions.test(parentAnchor.href)) {
            potentialBetterUrl = parentAnchor.href;
        }

        if (target.tagName.toLowerCase() === 'img') {
            imageUrl = target.src;
            imageTitle = target.alt.trim() || '';
        } else if (target.style.backgroundImage) {
            imageUrl = target.style.backgroundImage.replace(/url\(["']?([^"']+)["']?\)/, '$1');
        }

        if (potentialBetterUrl) {
            imageUrl = potentialBetterUrl;
        }

        if (imageUrl === lastProcessedUrl) {
            return; 
        }
        lastProcessedUrl = imageUrl;

        const ytMatch = imageUrl.match(/\/vi\/([a-zA-Z0-9_-]{11})\//);
        if (ytMatch) {
            imageUrl = `https://i.ytimg.com/vi/${ytMatch[1]}/maxresdefault.jpg`;
            console.log(`YouTube thumbnail detected. Switched to maxresdefault: ${imageUrl}`);
        }

        if (!imageTitle) {
            const parentAnchor = target.closest('a');
            if (parentAnchor && parentAnchor.href) {
                imageTitle = parentAnchor.href.split('/').pop().split('?')[0];
            }
        }

        if (!imageTitle) {
            imageTitle = imageUrl ? imageUrl.split('/').pop().split('?')[0] : 'unknown_image';
        }

        imageTitle = imageTitle.replace(/[\/:*?"<>|]/g, '_'); // Make filename safe

        if (!validExtensions.test(imageTitle)) {
            const extensionMatch = imageUrl ? imageUrl.match(validExtensions) : null;
            const extension = extensionMatch ? extensionMatch[0] : '.jpg'; // Default to .jpg
            imageTitle += extension;
        }

        const existingImage = preprocessedImages.find(img => img.url === imageUrl);
        if (!existingImage) {
            preprocessedImages.push({ url: imageUrl, title: imageTitle });
            if (preprocessedImages.length > maxHistory) {
                preprocessedImages.shift(); 
            }
            console.log(`Preprocessed image: URL=${imageUrl}, Title=${imageTitle}`);
        }

        lastHoveredImage = { url: imageUrl, title: imageTitle };
    }

    document.addEventListener('mousemove', function (event) {
        if (event.target.tagName.toLowerCase() === 'img' || event.target.style.backgroundImage) {
            preprocessImage(event.target); 
        }
    });

    function setCursorLoading(isLoading) {
        if (isLoading) {
            document.body.style.cursor = 'progress'; 
        } else {
            document.body.style.cursor = ''; 
        }
    }

    function processDownloadQueue() {
        if (isDownloading || downloadQueue.length === 0) return; 

        const nextImage = downloadQueue.shift();
        isDownloading = true;
        setCursorLoading(true); 

        GM_download({
            url: nextImage.url,
            name: nextImage.title,
            onerror: function (err) {
                console.error('Failed to download the image:', err);
                isDownloading = false; 
                setCursorLoading(false); 
                processDownloadQueue(); 
            },
            onload: function () {
                console.log(`Downloaded image: ${nextImage.title}`);
                isDownloading = false; 
                setCursorLoading(false); 
                processDownloadQueue(); 
            }
        });
    }


    document.addEventListener('keydown', function (event) {
        // Ignore the keypress if the target is an input or textarea
        const activeElement = document.activeElement;
        const isInputField = activeElement.tagName.toLowerCase() === 'input' ||
                             activeElement.tagName.toLowerCase() === 'textarea' ||
                             activeElement.isContentEditable;

        if (isInputField) return; // Do not download if the user is typing in an input field

        if (event.key.toLowerCase() === 's' && lastHoveredImage) {
            downloadQueue.push(lastHoveredImage);
            console.log(`Added image to queue: ${lastHoveredImage.title}`);
            processDownloadQueue(); 
        }
    });
})();