I have an audio stream from an external server and am not able perform any serverside changes. It currently works pretty well but it's only able to stream the songs in an HTML5 audio element. I'd also like to implement a download feature, the problem is, a link doesn't download anything, it automatically streams the mp3. The HTML5 download attribute doesn't do anything.
The complete Response Headers by the server:
Accept-Ranges:bytes
Cache-Control:no-cache, no-store, must-revalidate
Connection:close
Content-Length:6991749
Content-Type:audio/mpeg
Date:Sun, 28 Apr 2013 19:40:49 GMT
Expires:Sat, 26 Jul 1997 05:00:00 GMT
Last-Modified:Thu, 10 Jan 2013 18:59:31 GMT
Server:nginx/1.0.2
It should work completely in JavaScript, if possible without PHP proxy.
It turns out my initial pessimism (about this being impossible) might have misguided. Here is a demo that makes use of some of the HTML5 File API (not as advanced as some of the stuff I've been reading about, but it seems security limitations make totally automating this a bit out of reach at the moment, this demo works in Firefox and Chrome but I would guess only IE10 could stand a chance at supporting it.
var createObjectURL = function (file) {
if (window.webkitURL) {
return window.webkitURL.createObjectURL(file);
} else if (window.URL && window.URL.createObjectURL) {
return window.URL.createObjectURL(file);
} else {
return null;
}
},
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png', true);
xhr.responseType = 'blob';
xhr.onload = function (e) {
if (this.status == 200) {
var url = createObjectURL(new Blob([this.response], {
type: 'image/png'
}));
var link = document.createElement('A');
link.setAttribute('href', url);
link.setAttribute('Download', 'Name I Want it to have.png');
link.appendChild(document.createTextNode('Download'));
document.getElementsByTagName('body')[0].appendChild(link);
}
};
xhr.send();
Here I am using XMLHttpRequest to request a PNG, then I'm storing it in a Blob and creating a download URL with some extra information that triggers the browser to download the asset instead of just linking to it (which is what it would do with a PNG). I couldn't find a Grooveshark URL that didn't require some session key, so I don't know if this will work for you, but that limitation comes from Groovshark's efforts to prevent hot linking to songs.
I did it now,
the problem was, that the server automatically refused access to the temporary created Stream URI when it was requested once. I just commented out the HTML5 audio element and only placed an download link with the new HTML5 Download attribute
<a href="stream.com/stream.mp3" download="filename.mp3">
If i would not have set the "download" attribute, the browser would have automatically streamed the file.
Thumbs up to HTML5!
Related
How can I get the contents of a file using JS, while letting the file be cached by the browser?
One possible way is to make that file a .js and let it be var SuperVar = 'BASE64-ENCODED-CONTENT' (base64 to escape special chars), but access and maintenance of the real contents would become indeed hard. I am trying to have normal files after all.
As the files are in size of 1-100 KB and of an unlimited quantity, so is localStorage not an option (will run out of space).
Have tried with <iframe>. Browsers parse .html files somewhat fine. Files need to begin with <html> else they get wrapped in a <pre> tag. By other filetypes IE creates an <object> and offers the file for download.
The point is for JS to work with the same file contents on multiple page loads without downloading them every time.
You can simply use AJAX, which will use the cache, if your server is configured correctly, and if you make GET requests.
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.response.substr(0, 20));
};
xhr.open('GET', 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js');
xhr.send();
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Open your dev-tools Network panel to see how it has been transferred.</p>
<button id="btn">request jQuery</button>
You have to send cache-control header from your server to let browser cache your ajax request.
index.html
<button id="btn">GET</button>
<script>
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.response);
};
xhr.open('GET', 'cached.php');
xhr.send();
};
</script>
cached.php
<?php
header('Cache-Control: private, must-revalidate, max-age=60');
echo file_get_contents("file.any");
file.any
Contents
of
File...
You will see the status code 200, but if you check the Size column
in chrome developer-tools you can see if it was loaded from cache.
I'm loading a motion jpeg from third-party site, which I can trust. I'm trying to getImageData() but the browser (Chrome 23.0) complains that:
Unable to get image data from canvas because the canvas has been tainted by
cross-origin data.
There are some similar questions on SO, but they are using local file and I'm using third party media. My script runs on a shared server and I don't own the remote server.
I tried img.crossOrigin = 'Anonymous' or img.crossOrigin = '' (see this post on the Chromium blog about CORS), but it didn't help. Any idea on how can I getImageData on a canvas with cross-origin data? Thanks!
You cannot reset the crossOrigin flag once it is tainted, but if you know before hand what the image is you can convert it to a data url, see Drawing an image from a data URL to a canvas
But no, you cannot and should not be using getImageData() from external sources that don't support CORS
While the question is very old the problem remains and there is little on the web to solve it. I came up with a solution I want to share:
You can use the image (or video) without the crossorigin attribute set first and test if you can get a HEAD request thru to the same resource via AJAX. If that fails, you cannot use the resource. if it succeeds you can add the attribute and re-set the source of the image/video with a timestamp attached which reloads it.
This workaround allows you to show your resource to the user and simply hide some functions if CORS is not supported.
HTML:
<img id="testImage" src="path/to/image.png?_t=1234">
JavaScript:
var target = $("#testImage")[0];
currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax({
url: currentSrcUrl,
type:'HEAD',
withCredentials: true
})
.done(function() {
// things worked out, we can add the CORS attribute and reset the source
target.crossOrigin = "anonymous";
target.src = currentSrcUrl;
console.warn("Download enabled - CORS Headers present or not required");
/* show make-image-out-of-canvas-functions here */
})
.fail(function() {
console.warn("Download disabled - CORS Headers missing");
/* ... or hide make-image-out-of-canvas-functions here */
});
Tested and working in IE10+11 and current Chrome 31, FF25, Safari 6 (Desktop).
In IE10 and FF you might encounter a problem if and only if you try to access http-files from a https-script. I don't know about a workaround for that yet.
UPDATE Jan 2014:
The required CORS headers for this should be as follows (Apache config syntax):
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"
the x-header is required for the ajax request only. It's not used by all but by most browsers as far as I can tell
Also worth noting that the CORS will apply if you are working locally regardless of if the resource is in the same directory as the index.html file you are working with. For me this mean the CORS problems disappeared when I uploaded it to my server, since that has a domain.
You can use base64 of the image on canvas,
While converting into base64 you can use a proxy URL (https://cors-anywhere.herokuapp.com/) before your image path to avoid cross-origin issue
check full details here
https://stackoverflow.com/a/44199382/5172571
var getDataUri = function (targetUrl, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + targetUrl);
xhr.responseType = 'blob';
xhr.send();
};
getDataUri(path, function (base64) {
// base64 availlable here
})
Hello JavaScript gurus,
I need a file download functionality using XMLHttpRequest (with responseType="blob") that works in Safari 9+.
At the moment I'm using FileSaver.js like this:
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// using FileSaver.js to save blob
saveAs(xhr.response, filename);
// notify download finished, resolve promise
defer.resolve(true);
}
};
xhr.send();
which works fine in all main browsers but not in current version (9.x) of Safari.
I'll get a "Failed to load resource: Frame load interrupted". Usually a download is a zip file but I also tried to set "application/octet-stream".
I have one requirement: I need to know when then download has finished on client-side so using an iframe is no option (I guess).
I'm thankful for any hint how to download a file in Safari using XHR (no Flash).
Thanks,
Chris
Simple answer:
There is no solution!
See also: https://forums.developer.apple.com/message/119222
Thanks Safari ... my new almost IE6
I'm loading a motion jpeg from third-party site, which I can trust. I'm trying to getImageData() but the browser (Chrome 23.0) complains that:
Unable to get image data from canvas because the canvas has been tainted by
cross-origin data.
There are some similar questions on SO, but they are using local file and I'm using third party media. My script runs on a shared server and I don't own the remote server.
I tried img.crossOrigin = 'Anonymous' or img.crossOrigin = '' (see this post on the Chromium blog about CORS), but it didn't help. Any idea on how can I getImageData on a canvas with cross-origin data? Thanks!
You cannot reset the crossOrigin flag once it is tainted, but if you know before hand what the image is you can convert it to a data url, see Drawing an image from a data URL to a canvas
But no, you cannot and should not be using getImageData() from external sources that don't support CORS
While the question is very old the problem remains and there is little on the web to solve it. I came up with a solution I want to share:
You can use the image (or video) without the crossorigin attribute set first and test if you can get a HEAD request thru to the same resource via AJAX. If that fails, you cannot use the resource. if it succeeds you can add the attribute and re-set the source of the image/video with a timestamp attached which reloads it.
This workaround allows you to show your resource to the user and simply hide some functions if CORS is not supported.
HTML:
<img id="testImage" src="path/to/image.png?_t=1234">
JavaScript:
var target = $("#testImage")[0];
currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax({
url: currentSrcUrl,
type:'HEAD',
withCredentials: true
})
.done(function() {
// things worked out, we can add the CORS attribute and reset the source
target.crossOrigin = "anonymous";
target.src = currentSrcUrl;
console.warn("Download enabled - CORS Headers present or not required");
/* show make-image-out-of-canvas-functions here */
})
.fail(function() {
console.warn("Download disabled - CORS Headers missing");
/* ... or hide make-image-out-of-canvas-functions here */
});
Tested and working in IE10+11 and current Chrome 31, FF25, Safari 6 (Desktop).
In IE10 and FF you might encounter a problem if and only if you try to access http-files from a https-script. I don't know about a workaround for that yet.
UPDATE Jan 2014:
The required CORS headers for this should be as follows (Apache config syntax):
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"
the x-header is required for the ajax request only. It's not used by all but by most browsers as far as I can tell
Also worth noting that the CORS will apply if you are working locally regardless of if the resource is in the same directory as the index.html file you are working with. For me this mean the CORS problems disappeared when I uploaded it to my server, since that has a domain.
You can use base64 of the image on canvas,
While converting into base64 you can use a proxy URL (https://cors-anywhere.herokuapp.com/) before your image path to avoid cross-origin issue
check full details here
https://stackoverflow.com/a/44199382/5172571
var getDataUri = function (targetUrl, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + targetUrl);
xhr.responseType = 'blob';
xhr.send();
};
getDataUri(path, function (base64) {
// base64 availlable here
})
We're getting the following message from Chrome when downloading (or attempting to download) a pdf in our mobile web application.
"Warning: Something's not right here!... The site you are trying to access is acting strangely, and Chrome is unable to verify that the URL is correct."
This is working fine in Safari and essentially we are doing this.
On load do a call to verify that the document that we want to show is OK.
if the document is not ok message the user and then close the tab
Direct the tab to navigate to an address which downloads the PDF.
Without posting too much code the Javascript is something like this:
DoRequest ("print_report",
"VALIDATE",
mycallback);
function mycallback (data,error) {
var h_href = "";
var h_widget = "";
if(error == true) {
window.close();
return;
}
h_href = GenerateHREF( "print_report", "PRINT" );
window.location.href = h_href;
}
The URL provided by GenerateHREF is for the same originating site and is relative to the original.
the mime type is set to application/pdf.
The content-disposition is set to inline. I've tried setting the content-size header as well but it doesn't seem to have any effect.
Content-Disposition: attachment; filename="pp66.26.pdf"
Content-Length: 31706
Content-Type: application/pdf
I'm missing something ... just what?
Try to parse document to base64 and added to your document or iframe.
function getAsyncBase64(fileName, callBack){
var xhr = new XMLHttpRequest();
xhr.open('GET', fileName, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response || this.responseText);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var dataBinary = binaryString.join('');
var data64 = window.btoa(dataBinary);
callback(data64);
}
xhr.send();
};
function callback(base64){
window.open(base64, "_blank");
//or
iframe.src = "data:application/pdf;base64,"+ base64;
};
getAsyncBase64(url,callback);
If it's a popup/download issue you might be able to show it using an iframe?
<iframe src="downloads/report.pdf"></iframe>
I also think that popup behavior is probably high on the list of suspects (specifically the window.close(); line seems pretty suspicious especially if the popup is blocked by the user).
However, since the ultimate goal is to download the file, you could try changing the response headers to
Content-Disposition: attachment; filename="pp66.26.pdf"
Content-Length: 31706
Content-Type: applicaton/octet-stream
or you could try forcing all pdfs in a particular folder to force a download via .htaccess file, then just linking to them via the location.href you are using:
<FilesMatch "\.pdf$">
ForceType applicaton/octet-stream
Header set Content-Disposition attachment
</FilesMatch>