First of all there is a question with the same title here on SO but its not what I'm looking for and it doesn't have a complete answer either.
So here's my question. Say I have this URL which directs to an image.
https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg
Once I put this parameter ?dl=1
to the end of the URL, it becomes downloadable.
https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1
I'm trying to do this task through a userscript. So I used XMLHttpRequest for that.
var url = "https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1";
var request = new XMLHttpRequest();
request.open("GET", url, false);
request.send(null);
if (request.status === 200)
{
alert(request.statusText);
}
Here is a fiddle.
But it does not work.
The XMLHttpRequest method send() sends the request to the server. If the request is asynchronous (which is the default), this method returns as soon as the request is sent and the result is delivered using events. If the request is synchronous, this method doesn't return until the response has arrived.
XMLHttpRequest
will not work cross-domain, but since this is a userscript Chrome now supports GM_xmlhttpRequest()
in userscripts only.
Something like this should work, note that it is asynchronous:
GM_xmlhttpRequest ( {
method: 'GET',
url: 'https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1',
onload: function (responseDetails) {
alert(responseDetails.statusText);
}
} );
As for getting and using the actual image data, that is a major pain to work out.
You can use the new .responseType = "blob";
functionality in Firefox but Chrome does not yet support it.
In Chrome or Firefox, for the same domain only, you can use the new XHR2 like so:
See it in action at jsBin.
BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
var url = "http://jsbin.com/images/gear.png";
var request = new XMLHttpRequest();
request.open ("GET", url, false);
request.responseType = "arraybuffer";
request.send (null);
if (request.status === 200) {
var bb = new BlobBuilder ();
bb.append (request.response); // Note: not request.responseText
var blob = bb.getBlob ('image/png');
var reader = new FileReader ();
reader.onload = function (zFR_Event) {
$("body").prepend ('<p>New image: <img src="' + zFR_Event.target.result + '"></p>')
};
reader.readAsDataURL (blob);
}
GM_xmlhttpRequest()
does not (yet) support setting responseType
.
So, for GM script or userscript applications, we have to use a custom base64 encoding scheme like in "Javascript Hacks: Using XHR to load binary data".
The script code becomes something like:
var imgUrl = "http://jsbin.com/images/gear.png";
GM_xmlhttpRequest ( {
method: 'GET',
url: imgUrl,
onload: function (respDetails) {
var binResp = customBase64Encode (respDetails.responseText);
/*-- Here, we just demo that we have a valid base64 encoding
by inserting the image into the page.
We could just as easily AJAX-off the data instead.
*/
var zImgPara = document.createElement ('p');
var zTargetNode = document.querySelector ("body *"); //1st child
zImgPara.innerHTML = 'Image: <img src="data:image/png;base64,'
+ binResp + '">';
zTargetNode.parentNode.insertBefore (zImgPara, zTargetNode);
},
overrideMimeType: 'text/plain; charset=x-user-defined'
} );
function customBase64Encode (inputStr) {
var
bbLen = 3,
enCharLen = 4,
inpLen = inputStr.length,
inx = 0,
jnx,
keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789+/=",
output = "",
paddingBytes = 0;
var
bytebuffer = new Array (bbLen),
encodedCharIndexes = new Array (enCharLen);
while (inx < inpLen) {
for (jnx = 0; jnx < bbLen; ++jnx) {
/*--- Throw away high-order byte, as documented at:
https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
*/
if (inx < inpLen)
bytebuffer[jnx] = inputStr.charCodeAt (inx++) & 0xff;
else
bytebuffer[jnx] = 0;
}
/*--- Get each encoded character, 6 bits at a time.
index 0: first 6 bits
index 1: second 6 bits
(2 least significant bits from inputStr byte 1
+ 4 most significant bits from byte 2)
index 2: third 6 bits
(4 least significant bits from inputStr byte 2
+ 2 most significant bits from byte 3)
index 3: forth 6 bits (6 least significant bits from inputStr byte 3)
*/
encodedCharIndexes[0] = bytebuffer[0] >> 2;
encodedCharIndexes[1] = ( (bytebuffer[0] & 0x3) << 4) | (bytebuffer[1] >> 4);
encodedCharIndexes[2] = ( (bytebuffer[1] & 0x0f) << 2) | (bytebuffer[2] >> 6);
encodedCharIndexes[3] = bytebuffer[2] & 0x3f;
//--- Determine whether padding happened, and adjust accordingly.
paddingBytes = inx - (inpLen - 1);
switch (paddingBytes) {
case 1:
// Set last character to padding char
encodedCharIndexes[3] = 64;
break;
case 2:
// Set last 2 characters to padding char
encodedCharIndexes[3] = 64;
encodedCharIndexes[2] = 64;
break;
default:
break; // No padding - proceed
}
/*--- Now grab each appropriate character out of our keystring,
based on our index array and append it to the output string.
*/
for (jnx = 0; jnx < enCharLen; ++jnx)
output += keyStr.charAt ( encodedCharIndexes[jnx] );
}
return output;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With