NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Twitter Full-Resolution Image Downloader // @namespace https://openuserjs.org/users/Spacebat // @description Save full-res images from Twitter // @version 1.0 // @author Spacebat // @license MIT; http://opensource.org/licenses/MIT // @homepageURL https://twitter.com/MC_Spacebat/ // @supportURL https://twitter.com/MC_Spacebat/ // @updateURL https://openuserjs.org/meta/Spacebat/Twitter_Full-Resolution_Image_Downloader.meta.js // @include /^(?:http(?:s)?:\/\/)?(?:[^\.]+\.)?twitter\.com(?:\/.*)?$/ // @include /^(?:http(?:s)?:\/\/)?(?:[^\.]+\.)?twimg\.com(?:\/.*)?$/ // @require https://raw.githubusercontent.com/eligrey/FileSaver.js/master/FileSaver.js // ==/UserScript== if (!("contextMenu" in document.documentElement && "HTMLMenuItemElement" in window)) return; var body = document.body; body.addEventListener("contextmenu", initMenu, false); var menu = body.appendChild(document.createElement("menu")); menu.outerHTML = '<menu id="DTF-save-full-image" type="context">\ <menuitem label="Save full image"\ ></menuitem>\ </menu>'; document.querySelector("#DTF-save-full-image menuitem") .addEventListener("click", saveFullImage, false); function initMenu(aEvent) { var node = aEvent.target; var item = document.querySelector("#DTF-save-full-image menuitem"); if (node.localName == "img") { body.setAttribute("contextmenu", "DTF-save-full-image"); item.setAttribute("imageURL", node.src); } else { body.removeAttribute("contextmenu"); item.removeAttribute("imageURL"); } } function loadXHR(url) { return new Promise(function(resolve, reject) { try { var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "blob"; xhr.onerror = function() {reject("Network error.")}; xhr.onload = function() { if (xhr.status === 200) {resolve(xhr.response)} else {reject("Loading error:" + xhr.statusText)} }; xhr.send(); } catch(err) {reject(err.message)} }); } function saveFullImage(aEvent) { var imageURL = aEvent.target.getAttribute("imageURL"); var filename = imageURL.split("/").pop(); var fullImageURL = imageURL+':orig'; loadXHR(fullImageURL).then(blob => { saveAs(blob, filename); }); }