Bandcamp Download Link Grabber

Grab all download links from the bandcamp post-checkout download cart page

// ==UserScript==
// @name         Bandcamp Download Link Grabber
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  Grab all download links from the bandcamp post-checkout download cart page
// @author       Maff
// @match        https://bandcamp.com/download?*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bandcamp.com
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    var dataBindMatchStr = 'attr: { href: downloadUrl }, visible: downloadReady() && !downloadError()';
    var nDownloadables = {ready: 0, not: 0};

    function getBlock() {
        return document.getElementsByClassName('download_list')[0];
    }
    function getLinksFromDocument(box) {
        let elements = [].filter.call(getBlock().getElementsByTagName('a'), e => e.className == 'item-button');
        box.textContent = '';
        for(let link of elements) {
            if(link.hasAttribute('data-bind') && link.getAttribute('data-bind') == dataBindMatchStr) {
                if(link.href == '' || link.style.display == 'none') {
                    nDownloadables.not++;
                } else {
                    box.textContent += ''+link.href+'\n';
                    nDownloadables.ready++;
                }
            }
        }
    }
    function removeContainer() {
        let list = getBlock();
        if(list.children[0].id == 'tm_js_GrabDlLinks_Container') {
            list.children[0].remove();
        }
    }
    function createOrReplaceContainer() {
        removeContainer();
        let list = getBlock();
        let container = document.createElement('li');
        container.className = 'download_list_item';
        container.id = 'tm_js_GrabDlLinks_Container';
        container.style.flexDirection = 'column';
        list.prepend(container);
        return container;
    }
    function getContainer() {
        let list = document.getElementById('tm_js_GrabDlLinks_Container');
        if(list) {
            return list;
        }
        return createOrReplaceContainer();
    }
    function removeContainerById(id) {
        let container = document.getElementById(id);
        if(container) {
            container.remove();
        }
    }
    function createOrReplaceContainerById(id) {
        removeContainerById(id);
        let container = document.createElement('div');
        container.id = id;
        return container;
    }
    function addLinkBlock() {
        let container = getContainer();
        nDownloadables = {ready: 0, not: 0};
        removeContainerById('tm_js_GrabDlLinks_Output');
        let block = document.createElement('textarea');
        block.id = 'tm_js_GrabDlLinks_Output';
        block.style.minHeight = '800px';
        let info = document.createElement('span');
        removeContainerById('tm_js_GrabDlLinks_Info');
        info.id = 'tm_js_GrabDlLinks_Info';
        getLinksFromDocument(block);
        info.textContent = 'Ready to download: '+nDownloadables.ready+', preparing/failed: '+nDownloadables.not;
        container.appendChild(info);
        container.appendChild(block);
    }
    function addButton() {
        let container = getContainer();
        removeContainerById('tm_js_GrabDlLinks_Invoke');
        let link = document.createElement('a');
        link.id = 'tm_js_GrabDlLinks_Invoke';
        link.text = 'Get download links';
        link.onclick = addLinkBlock;
        container.prepend(link);
    }
    addButton();
})();