Download file when clicking on the link in Meteor - javascript

I store the mp3 files on my server using https://github.com/CollectionFS/Meteor-CollectionFS. I want to allow user to download the file just by clicking on the link and the 'download' attribute should work fine here i.e.:
download
The problem is that the file is opening/playing in the browser instead of just start to downloading to disk.
As discussed here https://code.google.com/p/chromium/issues/detail?id=373182 I guest it is because of cross origin request, so I tried to follow the suggested solution and use this link
download
with this handler
Template.podcastItemSummary.events({
'click a.btn-download': function(event, instance){
event.preventDefault();
downloadFile($(event.currentTarget).attr('data-url'));
}
});
if (Meteor.isClient) {
downloadFile = function(sUrl){
window.URL = window.URL || window.webkitURL;
var xhr = new XMLHttpRequest();
xhr.open('GET', sUrl, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
var res = xhr.response;
var blob = new Blob([res], {type:"audio/mp3"});
url = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = sUrl.split('/').pop();
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
};
xhr.send();
}
}
Now the file is downloaded as expected, but for large files there is a strange delay between 'click' and start of download. Any better solution?

As #ZuzEL wrote, the solution is to just end the link with ?download
download
I stored the url in a separate collection, and now I realized that I should store only the file's id (ubcq5Xev4mkQ3sv5t) as there is a by design solution https://github.com/CollectionFS/Meteor-CollectionFS/wiki/How-to:-Provide-a-download-button
Template.fileList.helpers({
files: function () {
return Files.find();
}
});
and template
<template name="fileList">
<div class="fileList">
{{#each files}}
<div class="file">
<strong>{{this.name}}</strong> Download
</div>
{{/each}}
</div>
</template>
which produces an url that includes a token as well
Download

Related

Javascript display filename instead of blob name in the PDF URL

I am able to get the pdf in the new window with URL as
htts://mydomainname/410-8d9c-4883-86c5-d76c50a24a1d
I want to remove the auto generated blob name (410-8d9c-4883-86c5-d76c50a24a1d) in the generated URL and place my custom name link below
htts://mydomainname/filename
What modifications i need to do for below code
var file = new Blob([response], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
$window.open(fileURL);
Not sure exactly where this code lives for you, but here is a solution using XmlHttpRequest "onload".
oReq.onload = function(e) {
if (this.status === 200) {
const blob = new Blob([oReq.response], { type: "image/pdf"})
let a = document.createElement("a");
a.style = "display: none";
document.body.appendChild(a);
let url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'myFile.pdf'; // gives it a name via an a tag
a.click();
window.URL.revokeObjectURL(url);
} else {
// handler error eee
}
}
Basically rather than $window.open(fileURL); you need to programmatically create a anchor tag, setting its href with the window.URL.createObjectURL as youve done above.
Hope this helps,
Matt

Download file from server folder to client pc

How can you download a file (.mp3) from a publicly accessible folder on the server to the clients pc?
I have tried:
let url = "\\public\\test.mp3";
let xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var a = document.createElement('a');
// xhr.response is a blob
a.href = window.URL.createObjectURL(xhr.response);
a.download = 'test.mp3';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
};
xhr.open('GET', url);
xhr.send();
But this just downloads the file with 15KB not the entire thing
Just navigate the user to the mp3 file:
window.location.href = '\\public\\test.mp3';

Download text file or image throw javascript on Firefox

I'm trying to download a file using a http link.
This is the code:
downloadFile: function (fileName, url) {
var link = document.createElement('a');
link.setAttribute('download', fileName);
link.setAttribute('type', 'application/octet-stream');
link.target = '_blank';
link.href = url;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
This works on Chrome and Edge but not on Firefox.
When I tried to download a text file or image, the browser opens a new tab this the file content rendered. I need that the browser open the default download window.
Is it possible?
This is an example of URL that I use: http://localhost:17671/docstmp/528d149e37467a53faeeeb0556901d87/ToDo.txt
I created this jsfiddle to demonstrate: jsfiddle.net/hp7yod85
The requested resource does not have Access-Control-Allow-Origin header set, and has X-Frame-Options header set to SAMEORIGIN to prevent loading into <iframe> element.
You can use YQL to retrieve content, then create a data URL of text content at returned results, then create an <a> element with href set to data URL. Returns expected result of opening dialog which prompts to open file within text editor or save file at firefox 47.
<!DOCTYPE html>
<html>
<body>
<button onclick="downloadFile()">Test</button>
<script>
function downloadFile() {
var request = new XMLHttpRequest();
var url = 'https://query.yahooapis.com/v1/public/yql?q='
+ 'select * from html where '
+ 'url="http://www.ietf.org/rfc/bcp/bcp47.txt"&format=json&callback='
request.open("GET", url);
request.onload = function() {
var data = JSON.parse(this.responseText).query.results.body.content;
var a = document.createElement("a");
a.href = "data:text/plain," + data;
a.download = "bcp47.txt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
request.send()
}
</script>
</body>
</html>
plnkr http://plnkr.co/edit/8JBBhVwIy0Icr2MaQZif?p=preview

Download files by script or something

In a web site, not mine, there a result to a search
<a href="show?file=191719&token=r1j">
<a href="show?file=191720&token=gh5">
<a href="show?file=191721&token=98j">
.....
<a href="show?file=191733&token=ty0">
and after I click on one of them I go to a page i fill a form and after I go to download page and i click on the link:
<a href="download?file=191719&token=r1j">
And i have to do that manually for 150 file wich is too long !!
what i want is by using a script or something, i download all the files directly by getting the file id in result page and put it in download link.
use this javascript snippet, where http://www.that-website.com/ is the url of that website, AND DO NOT download all files all at once if there are too many, download couple dozens each time by specifying start and finish file number, Note that the browser popup blocker will block this so you need to allow popup from this webpage in your popup blocker in your browser
JS:
var fileNumber,
start = 191719,
finish = 191729;
for(fileNumber = start; fileNumber <= finish; ++fileNumber){
window.open("http://www.that-website.com/download?file=" + fileNumber);
}
UPDATE:
Since random token are implemented in the url the easiest way is to enter it manually in multi-lines of window.open(), something like this:
window.open("http://www.that-website.com/download?file=191719&token=r1j");
window.open("http://www.that-website.com/download?file=191720&token=gh5");
window.open("http://www.that-website.com/download?file=191721&token=98j");
and so on for couple dozens.
UPDATE 2:
See an example of this in this JSFiddle
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- COPY BUNCH OF THE URLs AND PASTE THEM IN HERE THEN RELOAD THE PAGE, THEN REPEAT OVER AND OVER UNTIL IT IS ALL DONE! -->
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
$(document).ready(function(){
$('a').each(function(){
var showLink = $(this).attr('href');
var downloadLink = showLink.replace("show?file", "download?file");
window.open("http://www.example.com/" + downloadLink);
});
});
</script>
</body>
</html>
With the above code, this an HTML page ON YOUR COMPUTER, copy several original from that website page links - like: TEST to your local page and run it, still it is highly recommended that you paste 10-30 links each time.
You can generate links using excel, save it as txt file and download using wget with -i parameter.
You could use an XMLHttpRequest to download files in parallel as blobs and then use <a download>s to initiate download behaviour. This will have same-origin-policy restrictions though.
General idea is
// fetch
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
var uri = URL.createObjectURL(this.response); // generate URI to access Blob
// write, see below
});
xhr.open('GET', target_file_href);
xhr.responseType = 'blob'; // state we want the target as a blob/file
xhr.send(); // send the request
// ---------------
// write
var a = document.createElement('a');
a.href = uri;
a.setAttribute('download'); // make this a download link rather than a change page
document.body.appendChild(a);
a.click();
// cleanup a, uri
Here is a parallel file downloader I wrote in ES5 which limits the number of concurrent downloads.
function ParallelDownloader(max_parallel, retry_on_error) {
this.links = [];
this.current = 0;
this.max_parallel = max_parallel || 5;
this.retry_on_error = !!retry_on_error;
}
ParallelDownloader.prototype = Object.create(null);
ParallelDownloader.prototype.add = function (url) {
if ('splice' in url && 'length' in url)
this.links.push.apply(this.links, url);
else
this.links.push(url);
this.downloadNext();
};
ParallelDownloader.prototype.downloadNext = (function () {
function load() {
var a = document.createElement('a'),
uri = URL.createObjectURL(this.response),
cd = this.getResponseHeader('Content-Disposition'),
filename = null;
if (cd) {
cd = cd.match(/;\s+filename=(.+)/);
if (cd) filename = cd[1];
}
if (null === filename) {
cd = this.__url.match(/\/([^/]+?(?=\?|$))/);
if (cd) filename = cd[1];
}
if (null !== filename) a.setAttribute('download', filename);
else a.setAttribute('download');
a.setAttribute('href', uri);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(uri);
--this.__parallelDownloader.current;
this.__parallelDownloader.downloadNext();
}
function error() {
--this.__parallelDownloader.current;
if (this.__parallelDownloader.retry_on_error) {
console.warn('Will retry', this.__url);
this.__parallelDownloader.unshift(this.__url);
}
this.__parallelDownloader.downloadNext();
}
return function () {
var url;
++this.current;
if (this.current > this.max_parallel || this.links.length === 0) {
--this.current;
return;
}
url = this.links.shift();
var xhr = new XMLHttpRequest();
xhr.__parallelDownloader = this;
xhr.__url = url;
xhr.addEventListener('load', load);
xhr.addEventListener('error', error);
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
this.downloadNext();
};
}());
To use it you would do, e.g.
var pd = new ParallelDownloader(10); // max 10 concurrent downloads
pd.add([
'/path1.txt', '/path2.pub', '/path3.pdf'
]);
// or
pd.add('/path4.txt');
pd.add('/path5.txt');
// etc
Download attempt initiates as soon as a link is added and there is a slot free. (If you enable retry_on_error I haven't limited it so you may get infinite loops)

How can I know when the file download/"Save As" prompt appears?

I have a link on a page
<a class="btn btn-success" href="DownloadCsv">Download CSV</a>
When the user clicks on said link, the server responds with the header Content-Disposition: attachment to prompt the user with the "Save File" Dialog.
What I'd like to accomplish is: disable the link while the server is generating its response, and enable it once the server responds.
Is there any event fired for that response from the server? Or is there any other way to accomplish this?
The only way that comes to my mind is using AJAX.
You first download it with AJAX where you have events that guide you (like ready state etc.).
Then you do the actual download, but at that point it is served from the browsers cache.
So it is not actually downloaded but instantly loaded from disk.
The user will not tell the difference but you will be able to detect the end of the actual download.
I went through my old questions. I even don't remember what I need it for but I decided to answer on this now because it has not been solved yet after 3.5 years... It can be accomplished this way
Link can be
<a class="btn btn-success" onclick="clickHandler(this); return false;">Download CSV</a>
Handler
function clickHandler(element) {
//disable link
var href = element.href;
element.href = 'javascript:void(0)';
//download file
var xhr = new XMLHttpRequest();
xhr.open('GET', 'DownloadCsv', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) { binaryString[i] = String.fromCharCode(uInt8Array[i]); }
var data = binaryString.join('');
//initiate save as dialog
var base64 = window.btoa(data);
var a = document.createElement('a');
a.href = 'data:application/csv;base64,'+ base64;
a.setAttribute('download', 'data.csv');
a.click();
//enable link
element.href = href;
}
};
xhr.send();
}

Categories