// ==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 // @downloadURL none // ==/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; } })();