Twitter Original Image Extractor

Extract original size images for Twitter.

Verze ze dne 11. 05. 2020. Zobrazit nejnovější verzi.

// ==UserScript==
// @author   JimmyJin
// @name     Twitter Original Image Extractor
// @version  1.0.0
// @include       https://twitter.com*
// @description Extract original size images for Twitter.
// @namespace https://greasyfork.org/users/241557
// ==/UserScript==

javascript:(function(){
    function init() {
        getTweetData();
        setDOMObserver();
    }

    function setDOMObserver() {
        const DOMObserver = new MutationObserver(() => {
            getTweetData();
        });
        
        DOMObserver.observe(document.body, {
            attributes: true,
            childList: true,
            subtree: true
        });
    }

    function getTweetData() {
        const tweets = document.querySelectorAll("article");
        if (!isEmpty(tweets)) {
            tweets.forEach(tweet => {
                setTimeout(() => {
                    if (!hasButtonBeenCreated(tweet)) {
                        if (isArticle(tweet)) {
                            createButtonForArticle(tweet);
                        } else {
                            createButtonForTimeline(tweet);
                        }
                    }
                }, 300);
            });
        }
    }

    function isArticle(tweet) {
        if (!isEmpty(tweet)) {
            return tweet.getAttribute("class") == "css-1dbjc4n r-16y2uox r-1wbh5a2 r-1udh08x r-1j3t67a";
        }
    }

    function hasButtonBeenCreated(tweet) {
        if (isArticle(tweet)) {
            return document.querySelector("#buttonForArticle");
        } else {
            return document.querySelector(`#button${getTweetIdFromTweet(tweet)}`);
        }
    }

    function createButtonForArticle(tweet) {
        if (!isEmpty(tweet)) {
            const buttonBar = document.querySelector(".css-1dbjc4n.r-1oszu61.r-1gkumvb.r-1efd50x.r-5kkj8d.r-18u37iz.r-ahm1il.r-a2tzq0");
            const button = document.createElement("div");
            button.setAttribute("class", "css-1dbjc4n r-18u37iz r-1h0z5md r-3qxfft r-h4g966 r-rjfia");
            button.innerHTML = `<button></button>`;
            button.id = "buttonForArticle";
            button.style.marginTop = "2%";
            button.style.height = "50%";
            buttonBar.appendChild(button);
						
            button.addEventListener("click", () => {
                const imgs = getImageFromTweet(tweet);
                if (!isEmpty(imgs)) {
                    imgs.forEach(url => {
                        window.open(url);
                    });
                }
            });
        }
    }

    function createButtonForTimeline(tweet) {
        if (!isEmpty(tweet)) {
            const buttonBar = tweet.querySelectorAll(".css-1dbjc4n.r-18u37iz.r-1wtj0ep.r-156q2ks.r-1mdbhws")[0];
            const button = document.createElement("div");
            button.setAttribute("class", "css-1dbjc4n r-1mlwlqe r-18u37iz r-18kxxzh r-1h0z5md");
            button.innerHTML = `<button></button>`;
            button.id = `button${getTweetIdFromTweet(tweet)}`;
            buttonBar.lastChild.setAttribute("class", "css-1dbjc4n r-1iusvr4 r-18u37iz r-16y2uox r-1h0z5md");
            buttonBar.appendChild(button);
						
            button.addEventListener("click", () => {
                const imgs = getImageFromTweet(tweet);
                if (!isEmpty(imgs)) {
                    imgs.forEach(url => {
                        window.open(url);
                    });
                }
            });
        }
    }

    function getTweetIdFromTweet(tweet) {
        let result = null;
        if (!isEmpty(tweet)) {
            const linkObj = tweet.querySelectorAll("a.css-4rbku5.css-18t94o4.css-901oao.r-1re7ezh.r-1loqt21.r-1q142lx.r-1qd0xha.r-a023e6.r-16dba41.r-ad9z0x.r-bcqeeo.r-3s2u2q.r-qvutc0")[0];
            if (!isEmpty(linkObj)) {
                const href = linkObj.href;
                const lastSlashIndex = href.lastIndexOf("/");
                result = href.substr(lastSlashIndex + 1);
            }
        }
        return result;
    }

    function getImageFromTweet(tweet) {
        let result = null;
        if (!isEmpty(tweet)) {
            const imgs = tweet.querySelectorAll("img");

            if (!isEmpty(imgs)) {
                const srcArray = [];

                imgs.forEach(img => {
                    const pattern = /^https:\/\/pbs.twimg.com\/media\//;
                    const src = img.src;                 
                    if (src.match(pattern)) {
                        srcArray.push(src);
                    }
                });
                result = transImageUrlToOrig(srcArray);
            }
        }

        return result;
    }

    function transImageUrlToOrig(imgs) {
        const result = [];
        if (!isEmpty(imgs)) {
            imgs.forEach(img => {
                const questionMarkIndex = img.indexOf("?");
                const origUrl = img.substring(0, questionMarkIndex) + ".jpg:orig";
                result.push(origUrl);
            });
        }
        return result;
    }

    function isEmpty(data) {
        let result = false;
        if (data != undefined && data != null) {
            if (Array.isArray(data)) {
                if (data.length == 0) {
                    result = true;
                }
            } else if (typeof data == "string") {
                if (data.trim() == "") {
                    result = true;
                }
            }
        } else {
            result = true;
        }
        
        return result;
    }

    init();
})();