/fluttershy/ Upload images from URL

// ==UserScript==
// @name         Fluttershy Uploader from URL
// @namespace    Fluttershy-uploader
// @version      1.0
// @description  Upload image from URL, integrated into 8kun with Fluttershy style UI
// @match        https://8kun.top/*
// @grant        GM_xmlhttpRequest
// @connect      *
// ==/UserScript==

(function () {
  'use strict';

  function waitForElement(selector, timeout = 10000) {
    return new Promise((resolve, reject) => {
      const start = Date.now();
      const interval = setInterval(() => {
        const el = document.querySelector(selector);
        if (el) {
          clearInterval(interval);
          resolve(el);
        } else if (Date.now() - start > timeout) {
          clearInterval(interval);
          reject("Container not found in time.");
        }
      }, 500);
    });
  }

  function createUploader(container) {
    if (container.querySelector('.url-upload-wrapper')) return;

    const wrapper = document.createElement("div");
    wrapper.className = "url-upload-wrapper";
    wrapper.style.marginTop = "10px";
    wrapper.style.padding = "10px";
    wrapper.style.border = "1px dashed #fdd835";
    wrapper.style.borderRadius = "8px";
    wrapper.style.background = "#fff0f5";
    wrapper.style.fontSize = "0.8em";

    const toggleBtn = document.createElement("button");
    toggleBtn.textContent = "Upload image from URL";
    toggleBtn.type = "button";
    toggleBtn.className = "url-upload-toggle";
    toggleBtn.style.marginBottom = "6px";
    toggleBtn.style.background = "#fce4ec";
    toggleBtn.style.color = "#d6336c";
    toggleBtn.style.border = "1px solid #fdd835";
    toggleBtn.style.borderRadius = "6px";
    toggleBtn.style.padding = "6px 10px";
    toggleBtn.style.cursor = "pointer";
    toggleBtn.style.fontSize = "0.8em";

    const inputWrap = document.createElement("div");
    inputWrap.className = "url-upload-box";
    inputWrap.style.display = "none";

    const urlInput = document.createElement("input");
    urlInput.type = "text";
    urlInput.className = "url-input";
    urlInput.placeholder = "Paste a direct image URL";
    urlInput.style.width = "100%";
    urlInput.style.marginTop = "6px";
    urlInput.style.border = "1px solid #fdd835";
    urlInput.style.borderRadius = "4px";
    urlInput.style.padding = "6px";
    urlInput.style.background = "#fffafc";
    urlInput.style.color = "#c2185b";
    urlInput.style.fontSize = "0.8em";

    const uploadBtn = document.createElement("button");
    uploadBtn.textContent = "Upload";
    uploadBtn.type = "button";
    uploadBtn.className = "url-upload-btn";
    uploadBtn.style.marginTop = "6px";
    uploadBtn.style.background = "#f8bbd0";
    uploadBtn.style.color = "#880e4f";
    uploadBtn.style.border = "1px solid #fdd835";
    uploadBtn.style.borderRadius = "6px";
    uploadBtn.style.padding = "6px 10px";
    uploadBtn.style.cursor = "pointer";
    uploadBtn.style.fontSize = "0.8em";

    inputWrap.appendChild(urlInput);
    inputWrap.appendChild(uploadBtn);
    wrapper.appendChild(toggleBtn);
    wrapper.appendChild(inputWrap);
    container.appendChild(wrapper);
  }

  document.addEventListener('click', function (e) {
    if (e.target.matches('.url-upload-toggle')) {
      const box = e.target.nextElementSibling;
      if (box) {
        box.style.display = box.style.display === 'none' ? 'block' : 'none';
      }
    }

    if (e.target.matches('.url-upload-btn')) {
      const box = e.target.closest('.url-upload-box');
      const input = box.querySelector('.url-input');
      const imageUrl = input.value.trim();
      if (!imageUrl) return alert("Please enter a URL first.");

      const form = e.target.closest("form");
      const dropzone = form.querySelector(".dropzone");
      if (!dropzone) return alert("Dropzone not found in this form.");

      GM_xmlhttpRequest({
        method: "GET",
        url: imageUrl,
        responseType: "blob",
        onload: function (response) {
          if (response.status !== 200) {
            alert("Could not download the image. Is the URL valid?");
            return;
          }

          const blob = response.response;
          const filename = imageUrl.split('/').pop() || "image.png";
          const file = new File([blob], filename, { type: blob.type });

          const dt = new DataTransfer();
          dt.items.add(file);

          const dropEvent = new DragEvent("drop", {
            dataTransfer: dt,
            bubbles: true,
            cancelable: true
          });

          dropzone.dispatchEvent(dropEvent);
        },
        onerror: function () {
          alert("Error while downloading the image.");
        }
      });
    }
  });

  async function init() {
    try {
      const mainForm = await waitForElement("form[name='post']");
      createUploader(mainForm);
    } catch (err) {
      console.error("Main form not detected:", err);
    }

    const observer = new MutationObserver(() => {
      const qr = document.querySelector('#quick-reply');
      if (qr && qr.style.display !== 'none') {
        const qrForm = qr.querySelector("form");
        if (qrForm) createUploader(qrForm);
      }
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  window.addEventListener('load', init);
})();


F.A.Q.

What is this script for?

One of the most important and hardest-to-live-without features of 4chanX is the ability to upload images directly from a URL. This script enables that functionality, letting you copy an image URL from a booru (like Danbooru) and upload it here, no need to download the image first, re-upload it, or dig through your hard drive. Hope you flutterbros like it! The theme is inspired by her.

How to use it

  1. Once the script is installed, a new button labeled "Upload image from URL" will appear.
  2. Click it to open a simple upload menu. Paste the URL in the designated field and click Upload.
  3. Your image will appear automatically in the Attachments section. Now publish your post as usual.

How do I install it?"

Install Guide:

  1. How to Install Scripts in Firefox/Chrome (Tampermonkey, etc.):
    -Get a Userscript Manager:
    -Firefox/Chrome: Install Tampermonkey (Chrome Web Store / Firefox Add-ons).
    -Alternatives: Violentmonkey or Greasemonkey (same steps).
  2. Import the Script into Tampermonkey:
    -Open Tampermonkey’s dashboard (click its icon → "Dashboard").
    -Go to the "Utilities" tab.
  3. Paste the ##User Script code into the box.
    -Under "Install from clipboard", click "Import" → paste the code from above → "Install".
  4. Click "Install" or "Confirm".
Edit
Pub: 11 Jun 2025 12:15 UTC
Views: 9