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);
})();