Greasy Fork

Greasy Fork is available in English.

Bing Image Creator auto-download

Automatic image downloader for Bing Image Creator.

目前为 2024-11-07 提交的版本。查看 最新版本

// ==UserScript==
// @name         Bing Image Creator auto-download
// @namespace    http://tampermonkey.net/
// @version      Alpha-v3
// @license      MIT
// @description  Automatic image downloader for Bing Image Creator.
// @match        https://copilot.microsoft.com/images/create*?*autosavetimer=*
// @grant        GM_download
// @require      http://code.jquery.com/jquery-3.4.1.min.js
// ==/UserScript==
//
// I just pasted this together from things found scattered around the internet.  Primarily: https://github.com/Emperorlou/MidJourneyTools
//
// To enable periodic downloading of newly-created images, go to a 'recent creations' page, and add "&autosavetimer=60" to the URL;
// something like: `https://www.bing.com/images/create/-/1234?autosavetimer=60`.
//
// This implementation is designed to be left unattended - periodically reloading itself.  If you click a link it will disable the script,
// unless you remove `?*autosavetimer=*` from `@match` above.

(function() {
    'use strict';

    const downloadables = "img[src$='&pid=ImgGn']";
    const downloadInterval = 600;
    var activeDownloads = 0;
    var loadErrors = 0;
    var pollRate = 60000;

    function get_download_url(img) {
      const src = img.attributes.src.nodeValue;
      return src.replaceAll(/\&[whco]=\d*/g, "");
    }

    function get_img_id(src) {
        var url = new URL(src);
        return url.searchParams.get('id') || url.pathname.split('/').pop();
    }

    function get_filename(img, src, ref) {
        var url = new URL(src);
        var refurl = new URL(ref);
        var src_filename = get_img_id(src);
        var ref_path = refurl.pathname.split('/');
        while (ref_path.length && ref_path.shift() != 'create')
            ;
        var desc = (ref_path.length >= 2 && ref_path[0]) || refurl.searchParams.get('q') || img.getAttribute("alt");
        var pageid = (ref_path.length >= 2 && ref_path[1]) || refurl.searchParams.get('id') || "";

        return src_filename + "_" + pageid + "_" + desc + ".jpg";
    }

    function find_href(elem) {
        while (elem) {
            if (elem.hasAttribute('href')) return elem.href;
            elem = elem.parentElement;
        }
        return null;
    }

    $(document).ready(() => {
        var new_images = document.createElement("div");
        new_images.setAttribute("id", "newimages");
        new_images.setAttribute("hidden", "");
        document.body.append(new_images);

        var params = new URLSearchParams(window.location.search);
        pollRate = (params.get('autosavetimer') || 60) * 1000;
        setTimeout(reload, 1000);
    });

    function reload() {
        if (activeDownloads > 0) {
            console.log("active downloads:", activeDownloads);
        }
        var href = location.href + " #girrc";
        var target = $("#newimages");
        var result = target.load(href, function(response, status, xhr) {
            var delay = 1000;
            if ( status == "error" ) {
                console.log("problem loading content");
                loadErrors++;
                if (loadErrors > 10) {
                    console.log(loadErrors, "consecutive load errors");
                }
            } else {
                loadErrors = 0;
                var allImages = $(target.find(downloadables).get().reverse());
                for (const img of allImages) {
                    const src = get_download_url(img);
                    if (isUrlReady(src)) {
                        const ref = find_href(img) || "https://www.example.com/";
                        const filename = get_filename(img, src, ref);
                        if (filename) {
                            downloadFile(delay, src, filename, ref);
                            delay += downloadInterval;
                        } else {
                            console.log("something wrong with:", img);
                        }
                    }
                }
            }
            setTimeout(reload, pollRate + delay);
        });
    }

    function downloadFile(delay, url, filename, referrer) {
        setUrlBusy(url);
        setTimeout(function() {
            console.log("downloading", filename);
            const download = GM_download({
                url: url,
                name: "bing/" + filename,
                saveAs: false,
                conflictAction: "uniquify",
                onload: function () {
                    setUrlSaved(url);
                },
                onerror: function () {
                    console.log("error downloading", url);
                    clearUrlBusy(url);
                },
                ontimeout: function () {
                    console.log("timeout downloading", url);
                    clearUrlBusy(url);
                }
            });
        }, delay);
    };

    function setUrlBusy(src) {
        const id = "busyImage-" + get_img_id(src);
        sessionStorage.setItem(id, Date.now());
        activeDownloads++;
        if (activeDownloads > 1) console.log("concurrent downloads:", activeDownloads);
    }

    function clearUrlBusy(src) {
        const id = "busyImage-" + get_img_id(src);
        sessionStorage.removeItem(id);
        activeDownloads--;
    }

    function setUrlSaved(src) {
        const id = "savedImage-" + get_img_id(src);
        localStorage.setItem(id, true);
        clearUrlBusy(src);
    }

    function isUrlSaved(src) {
        const id = "savedImage-" + get_img_id(src);
        return localStorage.getItem(id) === "true" ? true : false;
    }

    function isUrlReady(src) {
        if (!src || isUrlSaved(src)) return false;

        const id = "busyImage-" + get_img_id(src);
        const stamp = sessionStorage.getItem(id);
        if (!stamp) return true;
        if (Date.now() - stamp < 60000) {
            console.log("file has been busy too long (lost event?):", src);
            clearUrlBusy(src);
            return true;
        }
        console.log("still waiting to finish:", src);
        return false;
    }

})();