SmartFrame Downloader

Enables the download of high-resolution PNG images from a 'SmartFrame'

Per 12-03-2025. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         SmartFrame Downloader
// @namespace    hoixw
// @version      1.1
// @description  Enables the download of high-resolution PNG images from a 'SmartFrame'
// @author       hoixw
// @match        *://*/*
// @grant        none
// @run-at       document-start
// @license MIT
// ==/UserScript==

// Check if the flag is set in localStorage (uses run-at document start)
if (localStorage.getItem('runCodeAfterRefresh') === 'true') {
    // Remove the flag from localStorage
    localStorage.removeItem('runCodeAfterRefresh');

    /*
    This forces all shadow-roots created to be open. Closed shadow-roots, as used by the
    smartFrame, cannot be accessed through JS. That's why they exist.
    Open shadow-roots can, so this means we can just access it and grab the image.
    */
    const nativeAttachShadow = Element.prototype.attachShadow;
    // Override attachShadow but force mode open
    Element.prototype.attachShadow = function(init) {
        init.mode = "open";
        return nativeAttachShadow.call(this, init);
    };

    // Mask the override by patching toString so it returns a benign string
    Object.defineProperty(Element.prototype.attachShadow, 'toString', {
        value: function() {
            return "function attachShadow() { [native code] }";
        },
        writable: false,
    });

    var checkForSmartFrame = setInterval(function() {
        if (document.querySelector('smartframe-embed')) {
            clearInterval(checkForSmartFrame); // Stop checking once the element is found

            var smartFrame = document.querySelector('smartframe-embed');
            var styles = getComputedStyle(smartFrame);
            // Actual width and height of image are stored here
            var width = smartFrame.style.getPropertyValue('--sf-original-width');
            var height = smartFrame.style.getPropertyValue('--sf-original-height');

            // Correct width and height variables
            smartFrame.style.width = width + "px";
            smartFrame.style.maxWidth = width + "px";
            smartFrame.style.height = height + "px";
            smartFrame.style.maxHeight = height + "px";

            setTimeout(() => {
                var stage = smartFrame.shadowRoot.querySelector("canvas.stage");
                var url = document.createElement("canvas").toDataURL.call(stage);
                var a = document.createElement("a");
                var t = smartFrame.getAttribute("image-id").replace(/\s/g, '-') + ".png";
                a.href = url;
                a.download = t;
                a.click();
            }, 3000);
        }
    }, 1000);
} else {
    // Wait for the page to load completely (otherwise smart-frame won't exist)
    window.addEventListener('load', function() {
        if (document.querySelector('smartframe-embed')) {
            'use strict';

            var executeButton = document.createElement('button');
            executeButton.textContent = 'Download Hi-Res';

            executeButton.style.padding = '10px 20px';
            executeButton.style.backgroundColor = '#007BFF';
            executeButton.style.color = 'white';
            executeButton.style.border = 'none';
            executeButton.style.borderRadius = '5px';
            executeButton.style.cursor = 'pointer';
            executeButton.style.fontWeight = 'bold';
            executeButton.style.margin = '10px';

            // Attach a click event listener to the button
            executeButton.addEventListener('click', function() {
                // Sets localStorage flag for code to be run after refresh immediately
                localStorage.setItem('runCodeAfterRefresh', 'true');

                location.reload();
            });

            var smartFrameParent = document.querySelector('smartframe-embed').parentElement;
            smartFrameParent.appendChild(executeButton);
        }
    });
}