CustomWebView icon indicating copy to clipboard operation
CustomWebView copied to clipboard

Feature Request: Support for downloading `blob` URLs

Open coder0107git opened this issue 2 years ago • 1 comments

Could support be added to download blob: URLs? I have done some research on how this could be done. I found this issue which sounds like the current problem with downloading blob URLs. I made the following code to take care of a few concerns I had about the examples' code.

Code

(async function() {
    const blobUrl = null; // Some blob URL from App Inventor.
    const { revokeObjectURL } = URL; // Backup the original URL.revokeObjectURL method
    const restoreRevokeObjectURL = () => URL.revokeObjectURL = revokeObjectURL; // Restore the URL.revokeObjectURL method
    
    let Blob2Base64Finished = false;
	
    // Temporarily make the blob URL being downloaded not revocable.
    (function(url) {
        url.revokeObjectURL = objectUrl => {
            // Incase a different blob URL needs to be revoked
            if(objectUrl != blobUrl) {
                revokeObjectURL(objectUrl);
            }
			
            // Skip the interval check if it already completed
            if(Blob2Base64Finished === true) {
                revokeObjectURL(objectUrl);
                restoreRevokeObjectURL();
            } else {
                const interval = setInterval(() => {
                    if(Blob2Base64Finished === true) {
                        clearInterval(interval);

                        revokeObjectURL(objectUrl);
                        restoreRevokeObjectURL();
                    }
                }, 100);
            }
        }
    })(URL)
	
    // Convert a blob to a data URL
    function Base64PromiseFileReader(blob) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();

            reader.addEventListener("loadend", () => resolve(reader.result));
            reader.addEventListener("onerror", e => reject(e));

            reader.readAsDataURL(blob);
        });
    }
	
    function readBlobUrl(blobUrl) {
        return new Promise(async (resolve, reject) => {
            try {
            	// Convert the blob URL to a blob
                const blob = await (await fetch(blobUrl)).blob();
                
                // Convert the blob to a data URL
                resolve(await Base64PromiseFileReader(blob));
            } catch(e) {
                reject(e.message == "Failed to fetch" ? "Blob Revoked" : e);
            }
        });
    }
	
    const result = await readBlobUrl(blobUrl); // Get the data URL form the blob URL
    Blob2Base64Finished = true; // Tell the modified URL.revokeObjectURL that converting the blob to a data URL was completed
    
    // Gives the modified URL.revokeObjectURL a chance to run before replacing it with the original
    setTimeout(() => restoreRevokeObjectURL(), 150);
	
    // Return `result` to the app to be downloaded
})();

I don't know how hard it would be to actually implement the java part of this, but it looks like it would be pretty simple.

Thanks for this amazing extension @vknow360!

coder0107git avatar Apr 14 '23 05:04 coder0107git

I'll work on this but there is very thin possibility that it will work.

vknow360 avatar Jul 13 '23 04:07 vknow360

https://github.com/vknow360/CustomWebView/commit/0c3cdb662d69559f50ddbfdbf2a5842a46ab32f1 adds this feature

vknow360 avatar Aug 31 '24 06:08 vknow360