hnOsmium0001

irccloud upload to imgur (updated: support for batch)

Mar 14th, 2021
155
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Upload to Imgur
  3. // @namespace    http://github.com/hnOsmium0001/
  4. // @version      1.0
  5. // @description  Add option to upload to custom image hosting services
  6. // @author       You
  7. // @match        https://*.irccloud.com/*
  8. // @grant        none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12.     'use strict';
  13.  
  14.     const CLIENT_ID = "YOUR_CLIENT_ID";
  15.  
  16.     function hasClassPrefix(element, prefix) {
  17.         if (!element.getAttribute) return false;
  18.  
  19.         const classes = (element.getAttribute("class") || "").split();
  20.         return classes.some(x => x.startsWith(prefix));
  21.     }
  22.  
  23.     class ChildrenSelector {
  24.         constructor(elm) {
  25.             this.elm = elm;
  26.         }
  27.  
  28.         andThenTag(tag, alternativeElm) {
  29.             if (!this.elm) {
  30.                 this.elm = alternativeElm;
  31.                 return this;
  32.             }
  33.  
  34.             for (const child of this.elm.childNodes) {
  35.                 if (child.tagName === tag) {
  36.                     this.elm = child;
  37.                     return this;
  38.                 }
  39.             }
  40.             this.elm = alternativeElm;
  41.             return this;
  42.         }
  43.  
  44.         andThenClass(prefix, alternativeElm) {
  45.             if (!this.elm) {
  46.                 this.elm = alternativeElm;
  47.                 return this;
  48.             }
  49.  
  50.             for (const child of this.elm.childNodes) {
  51.                 if (hasClassPrefix(child, prefix)) {
  52.                     this.elm = child;
  53.                     return this;
  54.                 }
  55.             }
  56.             // Failed to find a matching children
  57.             this.elm = alternativeElm;
  58.             return this;
  59.         }
  60.  
  61.         accept(successful, failed) {
  62.             if (this.elm) {
  63.                 successful(this.elm);
  64.             } else {
  65.                 failed();
  66.             }
  67.         }
  68.     }
  69.  
  70.     const uploadContainer = document.getElementById('fileUploadForm');
  71.     let batchFile;
  72.     new ChildrenSelector(uploadContainer)
  73.         .andThenClass("batch")
  74.         .andThenClass("treeContainer")
  75.         .accept(e => { batchFile = e }, () => {});
  76.     let singleFile;
  77.     new ChildrenSelector(uploadContainer)
  78.         .andThenClass("single")
  79.         .andThenClass("previewWrapper")
  80.         .accept(e => { singleFile = e }, () => {});
  81.  
  82.     let inputBox;
  83.     (function checkSession() {
  84.         function init() {
  85.             // cb() is a global function provided by irccloud
  86.             inputBox = document.getElementById("bufferInputView" + cb().bid())
  87.         }
  88.  
  89.         if (window.hasOwnProperty('SESSION')) {
  90.             window.SESSION.bind('init', function () {
  91.                 init();
  92.                 window.SESSION.buffers.on('doneSelected', function () {
  93.                     init();
  94.                 });
  95.             });
  96.         } else {
  97.             setTimeout(checkSession, 100);
  98.         }
  99.     })();
  100.  
  101.     function uploadImage(imageData, outArray, callback) {
  102.         const FILTER = ";base64,";
  103.         const data = new FormData();
  104.         data.append("image", imageData.substring(imageData.indexOf(FILTER) + FILTER.length));
  105.  
  106.         const req = new XMLHttpRequest();
  107.         req.onreadystatechange = () => {
  108.             if (req.readyState == 4) {
  109.                 // Response should contain a URL to the uploaded image
  110.                 const response = JSON.parse(req.response);
  111.                 console.log("[Upload Imgur] Uploaded image, response: ");
  112.                 console.log(response);
  113.                 if (outArray) {
  114.                     outArray.push(response);
  115.                 } else {
  116.                     inputBox.value += response.data.link;
  117.                 }
  118.                 if (callback) {
  119.                     callback(response);
  120.                 }
  121.             }
  122.         };
  123.         // For whatever reason, the actual endpoint for uploading image is /image instead of /upload as described at https://apidocs.imgur.com/#c85c9dfc-7487-4de2-9ecd-66f727cf3139
  124.         // See https://stackoverflow.com/questions/55733271/upload-image-to-imgur-failed-because-of-cors
  125.         req.open("POST", "https://api.imgur.com/3/image");
  126.         req.setRequestHeader("Authorization", `Client-ID ${CLIENT_ID}`);
  127.         req.send(data);
  128.     }
  129.  
  130.     function uploadAlbum(images) {
  131.         const data = new FormData();
  132.         // TODO the api suggests this instead of ids[], but for whatever reason this returns
  133.         // 403: You must own all the image deletehashes to add them to album <id>
  134.         //data.append("deletehashes", images.map(e => e.data.deletehash));
  135.         data.append("ids", images.map(e => e.data.id));
  136.  
  137.         const req = new XMLHttpRequest();
  138.         req.onreadystatechange = () => {
  139.             if (req.readyState == 4) {
  140.                 const response = JSON.parse(req.response);
  141.                 console.log("[Upload Imgur] Uploaded album, response:");
  142.                 console.log(response);
  143.                 inputBox.value += `https://imgur.com/a/${response.data.id}`;
  144.             }
  145.         };
  146.         req.open("POST", "https://api.imgur.com/3/album");
  147.         req.setRequestHeader("Authorization", `Client-ID ${CLIENT_ID}`);
  148.         req.send(data);
  149.     }
  150.  
  151.     new ChildrenSelector(uploadContainer)
  152.         .andThenClass("buttons")
  153.         .accept(uploadButtonContainer => {
  154.             const uploadBtn = document.createElement("button");
  155.             const closeBtn = uploadButtonContainer.lastElementChild;
  156.             uploadButtonContainer.prepend(uploadBtn);
  157.             uploadBtn.type = "button";
  158.             uploadBtn.classList.add("action");
  159.             uploadBtn.classList.add("confirm");
  160.             uploadBtn.innerHTML = "<span>Upload to Imgur</span>";
  161.             uploadBtn.addEventListener("click", () => {
  162.                 if (singleFile.hasChildNodes()) {
  163.                     const img = singleFile.children[0].children[0];
  164.                     uploadImage(img.src);
  165.                     closeBtn.click();
  166.                 }
  167.                 if (batchFile.hasChildNodes()) {
  168.                     const listElms = batchFile.children[0].children;
  169.                     const uploadResults = new Array(listElms.length);
  170.  
  171.                     let uploadedCount = 0;
  172.                     const uploadCallback = () => {
  173.                         uploadedCount++;
  174.                         if (uploadedCount >= listElms.length) {
  175.                             // All images has been uploaded
  176.                             uploadAlbum(uploadResults);
  177.                         }
  178.                     };
  179.  
  180.                     for (let i = 0; i < listElms.length; i++) {
  181.                         const li = listElms[i];
  182.                         const img = li.children[0].children[0].children[0];
  183.                         uploadImage(img.src, uploadResults, uploadCallback);
  184.                     }
  185.                     closeBtn.click();
  186.                 }
  187.             });
  188.         }, () => console.log("Failed to find button list of fileUploadContainer"));
  189. })();
Add Comment
Please, Sign In to add comment