3

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.:

 <a href="/cfs/files/audio/ubcq5Xev4mkQ3sv5t/file.mp3" download="file.mp3">download</a>

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

<a href="#" download data-url="{{url}}" type="button" class="btn btn-default">download</a>

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?

ziomyslaw
  • 201
  • 2
  • 12
  • 1
    Is there a reason you are not using the meteor built-in `HTTP.get`? Also, this has nothing to do with cross-origin, because it isn't cross-origin. It's not even an absolute URL! It's a relative URL to your own server. No your problem has nothing to do with cross-origin, just downloading an mp3 rather than playing it. I'd expect there being some answers on that problem here, no? maybe this can help: http://stackoverflow.com/questions/3499773/download-mp3-instead-of-playing-in-browser-by-default – Christian Fritz Oct 08 '15 at 23:17
  • ps: the delay comes from the download happening before the download appearing in the browser, because the real download is done inside javascript and what you call download (what the user sees), is just extracting the Blob from the browser as a file (and should hence we super-fast in contrast). – Christian Fritz Oct 08 '15 at 23:19
  • To pile on @Christian Fritz's comment, the whole download is happening in js before the browser gets a file object to download. This may not even work on iOS or Safari. – Michel Floyd Oct 09 '15 at 02:52
  • 1
    try `href="{{url}}&download"`. It worked for me – ZuzEL Oct 09 '15 at 07:08
  • @ZuzEL Thanks! That's it! I wish to accept your response, but can't do this as you added comment instead of answer. – ziomyslaw Oct 10 '15 at 18:30

1 Answers1

2

As @ZuzEL wrote, the solution is to just end the link with ?download

<a href="/cfs/files/audio/ubcq5Xev4mkQ3sv5t/file.mp3?download" target="_parent">download</a>

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> <a href="{{this.url download=true}}" class="btn btn-primary" target="_parent">Download</a>
      </div>
    {{/each}}
  </div>
</template>

which produces an url that includes a token as well

<a href="/cfs/files/audio/WdBfMy2gSLRwx3XKw/file.mp3?token=eyJhdXRoVG9rZW4iOiJ2bHd6WGNoT3ktUzNoOTJUUHJnLXFMZDd6OE9yS3NHMFNkaGMwbTRKWVVUIn0%3D&amp;download=true" target="_parent">Download</a>
ziomyslaw
  • 201
  • 2
  • 12
  • +1 anyway. I didn't know that `{{this.url download=true}}`. Don't remember if they documented something like this or not – ZuzEL Oct 10 '15 at 18:46