Download Youtube Custom Emojis

Add a button to download emojis and badges!

// ==UserScript==
// @name         Download Youtube Custom Emojis
// @namespace    https://greasyfork.org/en/scripts/502239-download-youtube-custom-emojis
// @version      0.9
// @description  Add a button to download emojis and badges!
// @author       ATPPP3
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip-utils/0.1.0/jszip-utils.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
// @license      MIT
// ==/UserScript==


(function () {
    function dlBadges(name, elems) {
        downloadImages(getImagesForNotMembership(elems, false), name, 'Badge');
    }

    //Download emojis
    function dlEmojis(name, elems) {
        downloadImages(getImagesForNotMembership(elems, false), name, 'Emoji');
    }

    function dlBadgesMem(name, elems) {
        downloadImages(getImagesForMembershipBadges(elems, false), name, 'Badge');
    }

    //Download emojis
    function dlEmojisMem(name, elems) {
        downloadImages(getImagesForMembershipEmojis(elems, false), name, 'Emoji');
    }

    function notMembership() {
        console.log("nonMembership");
        let Channel = document.querySelectorAll('#page-header h1 > span')[0].textContent;
        let PerksContainer = document.querySelectorAll('#perks_section #perks ytd-sponsorships-perk-renderer #container #images-line');
        let Badges = PerksContainer[0]; //Badges element selector
        let Emojis = PerksContainer[1]; //Emojis element selector

        if (!Badges || !Emojis) return;
        //download button style
        let btnStyle = "margin-bottom:5px; border-radius: 15px; background-color: #3ea6ff; color: #000000; font-size: 16px; border: none; height: 32px; cursor: pointer;";

        //Insert Download Button
        Badges.insertAdjacentHTML("beforebegin", "<button id=\"badges-dl\" style=\"" + btnStyle + "\">Download</button>");
        Emojis.insertAdjacentHTML("beforebegin", "<button id=\"emojis-dl\" style=\"" + btnStyle + "\">Download</button>");

        //Handle Button Click
        document.getElementById('badges-dl').addEventListener('click', dlBadges.bind(null, Channel, Badges));
        document.getElementById('emojis-dl').addEventListener('click', dlEmojis.bind(null, Channel, Emojis));
    }

    function isMembership() {
        console.log("isMembership");
        let Channel = document.querySelectorAll('#page-header h1 > span')[0].textContent;
        let Badges = document.querySelectorAll('#container .badge-container .badge-icon'); //Badges element selector
        let Emojis = document.querySelectorAll('#container #images-line')[0].getElementsByTagName('img') //Emojis element selector

        //download button style
        let btnStyle = "margin-bottom:5px; border-radius: 15px; background-color: #3ea6ff; color: #000000; font-size: 16px; border: none; height: 32px; cursor: pointer;";

        //Insert Download Button
        document.querySelectorAll('#container .badge-container')[0].insertAdjacentHTML("afterend", "<button id=\"badges-dl\" style=\"" + btnStyle + "\">Download</button>")
        document.querySelectorAll('#container #images-line')[0].insertAdjacentHTML("beforebegin", "<button id=\"emojis-dl\" style=\"" + btnStyle + "\">Download</button>")

        //Handle Button Click
        document.getElementById('badges-dl').addEventListener('click', dlBadgesMem.bind(null, Channel, Badges));
        document.getElementById('emojis-dl').addEventListener('click', dlEmojisMem.bind(null, Channel, Emojis));
    }


    setInterval(function () {
        console.log("started")
        try {
            //Check if membership join button clicked
            let PerksPopupHidden = document.querySelectorAll('ytd-popup-container > tp-yt-paper-dialog')[0].getAttribute('aria-hidden');
            if (PerksPopupHidden) {
                document.getElementById('badges-dl').remove();
                document.getElementById('emojis-dl').remove();
                return;
            }
        } catch (err) {
            try {
                let PerksButtonStatus = !!document.querySelectorAll('#contents .expand-collapse-button button[aria-label="Show perks info"]')[0];
                if (PerksButtonStatus) {
                    document.getElementById('badges-dl').remove();
                    document.getElementById('emojis-dl').remove();
                    return;
                }
            } catch (err) {
                return;
            }
        }


        console.log("check end");
        //Create a download Button if not exists
        let perksShowed = !!0;
        if (!document.getElementById('badges-dl') && !document.getElementById('emojis-dl')) {
            let membership = document.querySelectorAll('#tabsContent .yt-tab-shape-wiz[tab-identifier="TAB_ID_SPONSORSHIPS"]');
            if (membership) {
                perksShowed = !!document.querySelectorAll('#contents .expand-collapse-button button[aria-label="Hide perks info"]')[0];
            }

            if (perksShowed) {
                isMembership();
            } else {
                notMembership();
            }
        }
    }, 1000);


    //get all emojis/badges image url
    const getImagesForNotMembership = (el, includeDuplicates = false) => {
        console.log("getImg non");
        let eles = [...el.getElementsByTagName('img')];
        let srcs = eles.map(img =>img.getAttribute('src'));
        let images = [...srcs].map(src=>src.split('=')[0]);
        return includeDuplicates ? images : [...new Set(images)];
    };
    //get all emojis/badges image url
    const getImagesForMembershipBadges = (el, includeDuplicates = false) => {
        console.log("get badges ismem");
        let Badges = [...el].map(el => el.getElementsByTagName('img')[0]).map(img => img.getAttribute('src').split('=')[0]);
        return includeDuplicates ? Badges : [...new Set(Badges)];
    };
    const getImagesForMembershipEmojis = (el, includeDuplicates = false) => {
        console.log("get emojis ismem");
        let Emojis = [...el].map(el => el.getAttribute('src').split('=')[0]); //Emojis element selector
        return includeDuplicates ? Emojis : [...new Set(Emojis)];
    };

    function downloadImages(urls, name, type) {
        let filename = name + '.zip';
        try{
            JSZipDownload(urls, filename, type);
        }catch(err){
            let delay = 100;
            let target = document.querySelectorAll('ytd-popup-container > tp-yt-paper-dialog')[0];
            if(!target){target = document.body;}
            downloadImagesWithDelay(urls, name, type, delay, target);
        }

    }

    function JSZipDownload(urls, filename, type) {
        console.log("jszip");
        let zip = new JSZip();

        let interval = 500;

        urls.forEach(function (url, i) {
            const name = `${type}_${i}.png`;
            JSZipUtils.getBinaryContent(url, function (err, data) {
                if (err) {
                    throw err; // or handle the error
                }
                zip.file(name, data, {binary: true});
                if (i === urls.length - 1) {
                    setTimeout(() => {
                        zip.generateAsync({type: 'blob'}).then(function (content) {
                            saveAs(content, filename);
                        })
                    }, interval);
                } else {
                    clearInterval(interval); // Stop interval when done
                }
            })
        })

    }
    function backupDownloadImage(url, filename, target) {
        return fetch(url)
            .then(response => response.blob())
            .then(blob => {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = filename;
            target.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            target.removeChild(a);
        })
            .catch(() => console.error('An error occurred while downloading the image.'));
    }

    function downloadImagesWithDelay(urls, name, type, delay, target) {
        let index = 0;

        function downloadNext() {
            if (index < urls.length) {
                const url = urls[index];
                const filename = `${name}_${type}_${index + 1}.png`;
                backupDownloadImage(url, filename, target);
                index++;
                setTimeout(downloadNext, delay); // Schedule next download
            }
        }

        downloadNext(); // Start the process
    }


})();