Skip to content

Instantly share code, notes, and snippets.

@agraves
Created October 23, 2024 21:06

Revisions

  1. agraves renamed this gist Oct 23, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. agraves created this gist Oct 23, 2024.
    119 changes: 119 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    // Function to check if element is visible in viewport
    const isVisible = (elem) => {
    const rect = elem.getBoundingClientRect();
    return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
    };

    // Function to parse srcset into array of URLs and widths
    const parseSrcset = (srcset) => {
    if (!srcset) return [];
    return srcset.split(',').map(src => {
    const [url, width] = src.trim().split(' ');
    return {
    url: url.trim(),
    width: parseInt(width) || 0
    };
    });
    };

    // Function to get best image URL from element
    const getBestImageUrl = (img) => {
    // If srcset exists, get the largest version
    if (img.srcset) {
    const sources = parseSrcset(img.srcset);
    const largest = sources.reduce((max, curr) =>
    curr.width > max.width ? curr : max,
    { width: 0, url: '' }
    );
    if (largest.url) return largest.url;
    }

    // Look for data-srcset as fallback
    if (img.dataset.srcset) {
    const sources = parseSrcset(img.dataset.srcset);
    const largest = sources.reduce((max, curr) =>
    curr.width > max.width ? curr : max,
    { width: 0, url: '' }
    );
    if (largest.url) return largest.url;
    }

    // Fallback to src
    return img.src;
    };

    // Function to clean up filename
    const cleanFilename = (filename) => {
    // Remove dimensions (e.g., _1296x)
    filename = filename.replace(/_\d+x(?=\.[^.]+$)/, '');
    // Remove everything after ? or #
    filename = filename.split(/[?#]/)[0];
    return filename;
    };

    // Function to download an image
    const downloadImage = (url, filename) => {
    // Clean up the URL
    const cleanUrl = url.split(/[?#]/)[0];

    // Get filename from URL and clean it
    filename = filename || cleanUrl.split('/').pop();
    filename = cleanFilename(filename);

    const a = document.createElement('a');
    a.href = cleanUrl;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    };

    // Main function to download top N visible images
    const downloadTopVisibleImages = (n = 5) => {
    // Get all images
    const images = Array.from(document.getElementsByTagName('img'));

    // Filter for visible images and get their best URLs
    const visibleImages = images
    .filter(img => isVisible(img))
    .map(img => {
    const url = getBestImageUrl(img);
    // Skip data:image URLs
    if (url.startsWith('data:')) return null;

    // Get the width from srcset or fallback to natural width
    let width = 0;
    if (img.srcset) {
    const sources = parseSrcset(img.srcset);
    width = Math.max(...sources.map(s => s.width));
    } else {
    width = img.naturalWidth;
    }

    return {
    element: img,
    size: width * (img.naturalHeight || width), // Estimate height if not available
    url: url
    };
    })
    .filter(img => img !== null)
    .sort((a, b) => b.size - a.size)
    .slice(0, n);

    // Download images
    visibleImages.forEach((img, index) => {
    const filename = img.url.split('/').pop();
    console.log(`Downloading image ${index + 1}/${n}: ${cleanFilename(filename)}`);
    setTimeout(() => downloadImage(img.url), index * 500);
    });

    return `Found ${visibleImages.length} visible images. Starting downloads...`;
    };

    // Execute with default of 5 images
    downloadTopVisibleImages(10);