Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Easily download all DALL-E prompt images with a button

There is currently no way (September 2022) to download all images for DALL-E at https://labs.openai.com/. Which made me write a quick and dirty script to download all images for the current prompt or for all of the prompts. If you need such functionality then you can copy-paste the code and paste it into the browser's developer tools (F12 as default). After pasting the code it should add two buttons in the header that you can click.
download buttons in header

Some notes:

  • It helps a lot to disable "Ask where to save each file before downloading" as otherwise you'll be spammed with prompts to download the files. And to change the download folder as it's 200 images for all the items.
    In chrome: Settings -> Downloads -> Uncheck the toggle button.
  • Since the items in the list to the right are lazy loaded it's good to scroll all the way to the bottom if downloading all the images.
  • Because this script uses timings it might fail to find the download buttons, and it'll then log the item in the list to the right, so you can mouseover the item, and it should highlight the element. You can then click the current prompt button for those items.
  • This searches for the text "Download" to find the download button. If DALL-E has localization you will have to change the DOWNLOAD for this line of code to what it is for you.
    if (item.textContent.toUpperCase().includes('DOWNLOAD')) {

The code to copy paste into developer tools:


/**
 * Get the items in the right panel and download for each item.
 */
async function downloadAllImages() {
  var items = document.querySelectorAll('.hist-task-link');
  for (let i = 0; i < items.length; i++) {
    const item = items.item(i);
    item.click();
    await awaitTimeout(2000);
    await downloadImagesForCurrent(item);
    await awaitTimeout(10);
  }
}

/**
 * Download all the items for an item in the right side panel.
 * Since the items are lazy loaded it helps to scroll all the way to the bottom first so all the items are loaded.
 */
function downloadImagesForCurrent(listItem) {
  const promise = new Promise(async (res) => {
    const extraButtons = document.querySelectorAll('.task-page-quick-actions-button');
    for (let i = 0; i < extraButtons.length; i++) {
      await downloadImage(extraButtons.item(i), listItem);
      await awaitTimeout(100);
    }

    res();
  });

  return promise;
}

/**
 * Download an image by clicking the ... and then the download button that appears.
 * It helps to disable "Ask where to save each file before downloading", eg in chrome:  Settings -> Downloads -> Uncheck that toggle button.
 */
async function downloadImage(extraButton, listItem) {
  extraButton.click();
  await awaitTimeout(50);
  const downloadButton = getLastDownloadButton();
  if (!downloadButton) {
    console.log('Could not find download button for', listItem);
    return;
  }

  downloadButton.click();
}

/**
 * We need to get the last download button because there might be multiple open at once.
 */
function getLastDownloadButton() {
  const selectableItems = document.querySelectorAll('.menu-item-selectable');
  for (let i = selectableItems.length - 1; i >= 0; i--) {
    const item = selectableItems.item(i);
    if (item.textContent.toUpperCase().includes('DOWNLOAD')) {
      return item;
    }
  }
}

/**
 * Adds an awaitable setTimeout since we need to wait for buttons.
 */
function awaitTimeout(delay) {
  return new Promise(res => setTimeout(() => res(), delay));
}

!function() {
  const header = document.querySelector('.app-header-contents');
  if (!header) {
    console.log('Could not find header element to add buttons, you need to use code manually.')
    console.log('downloadAllImages() - to download all images');
    console.log('downloadImagesForCurrent() - to download current prompt');
    return;
  }

  const downloadAllButton = document.createElement('button');
  downloadAllButton.innerText = 'Download All';
  downloadAllButton.onclick = downloadAllImages;

  const downloadCurrent = document.createElement('button');
  downloadCurrent.innerText = 'Download Current Prompt';
  downloadCurrent.onclick = downloadImagesForCurrent;

  header.appendChild(downloadAllButton);
  header.appendChild(downloadCurrent);
}();

Making a FFXIV ACT Chat extractor

This is about the making of Nuusie's Final Fantasy XIV Chat Extractor for the ACT Plugin.. And some of the obstacles encountered along the way. Some of the obstacles were custom colours, manipulating text to look like an emote, *Luna is writing a blog post*, quotation marks.
The chat extractor can be found here: https://github.com/saaratrix/nuu-ffxiv-act-chat-extractor

Introduction

The idea came from a friend who wanted to extract their stored chat logs and the tools she found was not as trustworthy to her as something made by me. For example this tool was hosted through a web server and she didn't want to upload her chat logs there. https://github.com/ErstonGreatman/ffxiv-act-chat-extractor.

Which lead to the first obstacle that I wanted to design the tool so you can run it locally and I wanted it to be lightweight. So that if someone does look through the code they can hopefully easily see that it just does what's expected. You could add the script and css bundles inside the html page so that it's still 1 single page but the file wouldn't look as readable. Even something smaller like Svelte still has 23 kb of minified javascript.

Developing everything in 1 file meant that I started using comments to try and separate things into sections. For example like this:


// ******************
// A section!
// ******************