NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Twitter HQ Photo Downloader // @version 1.0 // @description Click button to download HQ photo from twitter.com. // @author navchandar // @homepage https://github.com/navchandar // @copyright 2020, navchandar (https://openuserjs.org/users/navchandar) // @grant GM_openInTab // @grant GM_download // @grant GM_addStyle // @match *://*.twitter.com/* // @run-at document-end // @require http://code.jquery.com/jquery-3.4.1.min.js // @updateURL https://openuserjs.org/meta/navchandar/Twitter_HQ_Photo_Downloader.meta.js // @downloadURL https://openuserjs.org/install/navchandar/Twitter_HQ_Photo_Downloader.user.js // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABTVBMVEUdofIcofIaoPIboPIvqfNHs/RCsPQnpfMfovIho/I7rvQeofIjo/J4x/fU7f3w+f7s9/7A5ftYuvU6rfRyxPdEsfQ5rfTJ6Pxmv/Z/yvj4/P/////t+P7j8/204PtAsPROtfX0+v57yPclpPI4rPTd8f3J6fxuw/ceovJDsfTr9/624ftXufUlpfIWnvL5/f+S0vkmpfMkpPK24Pvy+v7B5fuHzfhcu/Z9yfj6/f/h8/01q/MuqPN3x/fm9f71+/7+///Z7/1GsvTe8f3z+v7C5vy64vuY1PlJs/XS7Pz2+/9kvvbO6vz+/v/F5/wqpvP2+/5nwPYopvOe1/mj2fpbu/a54vv9/v+84/syqvMgovKFzPj7/f+x3/s2q/NUuPWh2PrM6vyAyvgppvNNtfXH6Pzv+P7y+f7c8f18yPdHsvRLtPUzqvMio/IcoPJuec6iAAAAAWJLR0QbAmDUpAAAAAd0SU1FB+IEAxMjDa4VD/IAAAEXSURBVDjLY2AYpoCRiZkRU5QZLs3MwsrGzszMzIEiz8nFDZXn4eXjFxAUEhYRZUbWLyYuATGXUVJKGghkZOXkkY1gUlAUUFJmYmRgVlGVBgMpNXUNZBM0taSltHV0mfR0pCAK9A0MkV3KaGQMFDQxNTO3sIQosLJGdgIDo42tHUSjvQNEgSMLileZnJxdpFGAqxFq2Bi6ocpLu6PYAHSlh6cDsryXORN6+Hr7+CIp8PNHD21m2wAk+YBAdAMYGIOCkVSE8GBGFzNnaFg4VD4ikhldmjOKXTPaGSIdExuHIc8Rn5AoA/FGuGpSMoY8AwNPikGqbFq6QEZYphi25AIMS2ZDlaxszZxcJmYGHICRmYmJOY9heAIA9ZQq6UkXW+AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDQtMDNUMTk6MzU6MTMrMDI6MDAxgFSMAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTA0LTAzVDE5OjM1OjEzKzAyOjAwQN3sMAAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABXelRYdFJhdyBwcm9maWxlIHR5cGUgaXB0YwAAeJzj8gwIcVYoKMpPy8xJ5VIAAyMLLmMLEyMTS5MUAxMgRIA0w2QDI7NUIMvY1MjEzMQcxAfLgEigSi4A6hcRdPJCNZUAAAAASUVORK5CYII= // @license MIT // ==/UserScript== function getElementsByXPath(xpath, parent) { let results = []; let query = document.evaluate(xpath, parent || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (let i = 0, length = query.snapshotLength; i < length; ++i) { results.push(query.snapshotItem(i)); } return results }; function has(String, search) { try { if (String.indexOf(search) > -1) { return true; } } catch (err) {} return false; } function saveStory(zEvent) { let parent = document.elementFromPoint(innerWidth / 2, innerHeight / 2).parentNode.parentNode.parentNode.parentNode, video = parent.querySelector("video source"), image = parent.querySelector("img"); if (!video && !image) { parent = document.elementFromPoint(innerWidth / 2, innerHeight / 2).parentNode.parentNode.parentNode.parentNode.parentNode.parentNode; video = parent.querySelector("video source"); image = parent.querySelector("img"); } if (video) { GM_download(video.getAttribute("src"), "Twitter_vid.mp4"); } else if (image) { GM_download(image.getAttribute("src").replace('format=jpg', 'format=png').replace('name=small', 'name=large'), "Twitter_img.png"); } else { console.log("Nothing img/video found to save.") } } function openStory(zEvent) { let parent = document.elementFromPoint(innerWidth / 2, innerHeight / 2).parentNode.parentNode.parentNode.parentNode, video = parent.querySelector("video source"), image = parent.querySelector("img"); if (!video && !image) { parent = document.elementFromPoint(innerWidth / 2, innerHeight / 2).parentNode.parentNode.parentNode.parentNode.parentNode.parentNode; video = parent.querySelector("video source"); image = parent.querySelector("img"); } if (video) { GM_openInTab(video.getAttribute("src"), "Twitter_vid.mp4"); } else if (image) { GM_openInTab(image.getAttribute("src").replace('format=jpg', 'format=png').replace('name=small', 'name=large'), "Twitter_img.png"); } else { console.log("Nothing img/video found to open.") } } function AddButton() { // Add a button element on div var zNode = document.createElement('div'); zNode.innerHTML = '<button id="openButton" title="Click to open this photo" type="button">Open</button>'; zNode.setAttribute('id', 'myContainer1'); document.body.appendChild(zNode); zNode = document.createElement('div'); zNode.innerHTML = '<button id="saveButton" title="Click to download this photo" type="button">Save</button>'; zNode.setAttribute('id', 'myContainer2'); document.body.appendChild(zNode); //--- Activate the newly added button. document.getElementById("saveButton").addEventListener("click", saveStory, false); document.getElementById("openButton").addEventListener("click", openStory, false); //--- Style our newly added element using CSS. GM_addStyle(` #myContainer1{position:fixed;bottom:.25em;left:51%;right:48%;margin:0;width:5%;height:6%;text-align:center} #myContainer2{position:fixed;bottom:.25em;left:47%;right:48%;margin:0;width:5%;height:6%;text-align:center} #openButton{opacity:.55;cursor:pointer;background-color:#262626;color:White;font-size:12px;border-radius:7px;padding:2.5px} #saveButton{opacity:.55;cursor:pointer;background-color:#262626;color:White;font-size:12px;border-radius:7px;padding:2.5px} #saveButton:hover,#openButton:hover{color:White;opacity:1} `); } function HideBtn() { document.getElementById('openButton').style.visibility = 'hidden'; document.getElementById('saveButton').style.visibility = 'hidden'; } function UnHideBtn() { document.getElementById('openButton').style.visibility = 'visible'; document.getElementById('saveButton').style.visibility = 'visible'; } (function () { 'use strict'; AddButton(); HideBtn(); // call this every 2 seconds to update according to page load setInterval(function () { var hostURL = window.location.href; if (has(hostURL, 'twitter.com') && has(hostURL, 'photo')) { UnHideBtn(); } else { HideBtn(); } }, 2000); })();