The other day I encountered a problem, which is about how to download an audio mp3 from a website using Javascript. After a bit of search on Google, I found the answer. It’s actually quite simple. A user downloads a file from a website by clicking on a link and the browser downloads it. All you need to do is emulate the process using Javascript.

download0

function download0(url, name) {
  var link = document.createElement("a");
  link.download = name
  link.href = url;
  link.click();
  return false;
}

download0() is the simplest form to simulate the download, it does the following things:

  • create an HTML element <a>
  • set the HTML5 attribute download to the <a> element
  • set the href attribute of the <a> element
  • emulate the user click by calling click() on the <a> element

download1

Some improvements can be made. First, if the script is run on Google Chrome and the object to download is an mp3 file. Chrome will open the mp3 file in a tab and play it using a built-in player. This is really not the behavior we deisired. What we want is download the file directly, instead of playing it in tab. As I check check, there is no option I could find to tell Chrome to download the file directly. Chrome would only download a file rather than open it if the link to the file is clicked with ALT pressed down (on Windows) or with CMD pressed down (on Mac).

So, to emulate the ALT-Click or the CMD-Click. We can not just use link.click(), but something more complex. We must create a moust event and dispatch it. Here is the code:

  // create the event
  var evt = document.createEvent("MouseEvents");

  // init the event with ALT-Click
  evt.initMouseEvent("click", true, true, window,
    0, 0, 0, 0, 0,
    false, true, false, false,  // ctrl, alt, shift, meta
    0, null);

  // dispatch the event to the link
  link.dispatchEvent(evt)

The above code is for Windows. Since Mac uses CMD-Click, evt.initMouseEvent() should be fed with different parameters. To tell apart Windows or Mac, we can use navigator.platform supported by browsers. navigator.platform returns Win32 on Windows, and MacIntel on Mac.

Here is the code for download1, which incorportes all the improvements mentioned above:

function download1(url, name) {
  var link = document.createElement("a");

  link.download = name
  link.href = url;

  var evt = document.createEvent("MouseEvents");

  if (navigator.platform == "Win32") {
    evt.initMouseEvent("click", true, true, window,
      0, 0, 0, 0, 0,
      false, true, false, false,  // ctrl, alt, shift, meta
      0, null);
  } else if (navigator.platform == "MacIntel") {
    evt.initMouseEvent("click", true, true, window,
      0, 0, 0, 0, 0,
      false, false, false, true,  // ctrl, alt, shift, meta
      0, null);
  } else {
    console.log("unsupported navigator.platform", navigator.platform)
    return false
  }

  link.dispatchEvent(evt)

  return false;
}

(The End)