Last active
July 9, 2023 19:09
-
-
Save sidneys/1731ea8ca69af49ca6e138d045c09971 to your computer and use it in GitHub Desktop.
Userscript | Download File As
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Save-As Userscript Library | |
// @namespace de.sidneys.userscripts | |
// @homepage https://gist.githubusercontent.com/sidneys/1731ea8ca69af49ca6e138d045c09971/raw/ | |
// @version 3.0.0 | |
// @description "Save As..." for any URL | |
// @author sidneys | |
// @icon https://www.greasespot.net/favicon.ico | |
// @include *://*/* | |
// @grant unsafeWindow | |
// ==/UserScript== | |
/** | |
* @default | |
* @constant | |
*/ | |
DEBUG = false | |
/** | |
* @callback saveAsCallback | |
* @param {Error} error - Error | |
* @param {Number} progress - Progress fraction | |
* @param {Boolean} complete - Completion Yes/No | |
*/ | |
/** | |
* Download any file via XHR | |
* @param {String} url - Target URL | |
* @param {String=} name - Filename | |
* @param {saveAsCallback} callback - Callback | |
*/ | |
let saveAs = (url, name, callback = () => {}) => { | |
console.debug('saveAs') | |
// Parse URL | |
const urlObject = new URL(url) | |
const urlHref = urlObject.href | |
const urlFilename = urlObject.pathname.replace(/\?.*$/, '') | |
// Resolve filename | |
const filename = name || urlFilename | |
// Create XHR Request | |
const request = new XMLHttpRequest() | |
// XHR Open | |
request.open('GET', urlHref) | |
// XHR MIME Type | |
request.responseType = 'blob' | |
request.overrideMimeType('application/octet-stream') | |
// XHR Headers | |
request.setRequestHeader('Accept-Ranges', 'bytes') | |
request.setRequestHeader('Content-Disposition', 'attachment') | |
request.setRequestHeader('Content-Transfer-Encoding', 'binary') | |
request.setRequestHeader('Content-Type', 'application/octet-stream') | |
// Error handler | |
request.onerror = () => { | |
console.debug('saveAs', 'onerror') | |
callback(new Error('Network Request failed.')) | |
} | |
// Progress handler | |
request.onprogress = (event) => { | |
//console.debug('saveAs', 'onprogress') | |
callback(null, (event.loaded / event.total)) | |
} | |
// Completion handler | |
request.onload = (event) => { | |
console.debug('saveAs', 'onload', event) | |
console.info('onload', 'xhr.readyState', request.readyState) // readyState will be 1 | |
// Create new File object with generic MIME type | |
const file = new File([request.response], '', { type: 'application/octet-stream' }) | |
// Create ObjectURL | |
const objectUrl = window.URL.createObjectURL(file) | |
// Create helper element | |
const anchorElement = document.createElement('a') | |
anchorElement.style.display = 'none' | |
anchorElement.target = '_self' | |
anchorElement.href = objectUrl | |
anchorElement.download = filename | |
document.body.appendChild(anchorElement) | |
// Trigger download | |
anchorElement.click() | |
// Revoke ObjectURL | |
window.URL.revokeObjectURL(objectUrl) | |
// Remove element | |
anchorElement.remove() | |
callback(null, 1, true) | |
} | |
// XHR Send | |
request.send() | |
} | |
unsafeWindow.saveAs = saveAs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment