Sometimes, is not the user who needs to handle file downloads but you. Think about an application that requires some extra files to work as according to the every user, these files changes.
It wouldn't clever to let that the user handle the download of those files, as that's what Electron allow us to do, however that's not what we want.
In native languages like C#, Objective-C there are easy (theoretically) snippets that shows how to download a file in the OS without the user interaction. In this article we are going to expose a way in which you can download a file without so many workaround easily using Javascript in Electron with the help of node request library.
Requirements
- In this case, we are going to need the node request library.
Use the following command to include this library in your project :
npm install request
Downloading a file in your desktop
Before continue, declare the basic dependencies in the top of your script.
var request = require('request');
var fs = require('fs');
The filesystem will take care of write the file in our desktop while the request lib downloads it.
Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default. The Request library has a lot of awesome features that you may want to explore before using it. Thanks to this library we'll be able to stream any response and save it into a file.
The magic occurs with createWriteStream
, the function creates a writable stream in a very simple manner. After a call to fs.createWriteStream with the filepath, you have a writeable stream to work with. It turns out that the response (as well as the request) objects are streams. So we will stream the GET data to the file output.
Our solution is based on this principle and it's really easy to use and understand :
function downloadFile(file_url , targetPath){
// Save variable to know progress
var received_bytes = 0;
var total_bytes = 0;
var req = request({
method: 'GET',
uri: file_url
});
var out = fs.createWriteStream(targetPath);
req.pipe(out);
req.on('response', function ( data ) {
// Change the total bytes value to get progress later.
total_bytes = parseInt(data.headers['content-length' ]);
});
req.on('data', function(chunk) {
// Update the received bytes
received_bytes += chunk.length;
showProgress(received_bytes, total_bytes);
});
req.on('end', function() {
alert("File succesfully downloaded");
});
}
function showProgress(received,total){
var percentage = (received * 100) / total;
console.log(percentage + "% | " + received + " bytes out of " + total + " bytes.");
}
Note
The progress is retrieven according to the filesize in bytes of the file and the total of received bytes (which are added to received_bytes
on every data event).
To download a file, use the downloadFile method. This method expects as first parameter the web URL of the resource and as second parameter the local directory where the file will be saved (including filename and extension).
downloadFile("http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg", "/var/www/downloads/butterfly-wallpaper.jpeg");
Finally, you only need to be worry about providing a valid local path. You can use a folder selector and then provide a filename, or just provide a static path and retrieve only the original name.
var fileURL = "http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg";
// butterfly-wallpaper.jpeg
var filename = getFilenameFromUrl(fileURL);
var downloadsFolder = "C:\\Users\\sdkca\\Downloads";
function getFilenameFromUrl(url){
return url.substring(url.lastIndexOf('/') + 1);
}
var finalPath = downloadsFolder + "\\" + filename;
downloadFile(fileURL, finalPath);
Promise based implementation
If you don't like to work with so many callbacks, then probably you are a Promises guy. The following snippet implements the same code to download a file but with promises:
/**
* Promise based download file method
*/
function downloadFile(configuration){
return new Promise(function(resolve, reject){
// Save variable to know progress
var received_bytes = 0;
var total_bytes = 0;
var req = request({
method: 'GET',
uri: configuration.remoteFile
});
var out = fs.createWriteStream(configuration.localFile);
req.pipe(out);
req.on('response', function ( data ) {
// Change the total bytes value to get progress later.
total_bytes = parseInt(data.headers['content-length' ]);
});
// Get progress if callback exists
if(configuration.hasOwnProperty("onProgress")){
req.on('data', function(chunk) {
// Update the received bytes
received_bytes += chunk.length;
configuration.onProgress(received_bytes, total_bytes);
});
}else{
req.on('data', function(chunk) {
// Update the received bytes
received_bytes += chunk.length;
});
}
req.on('end', function() {
resolve();
});
});
}
And its usage still very simple:
downloadFile({
remoteFile: "http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg",
localFile: "/var/www/downloads/butterfly-wallpaper.jpeg",
onProgress: function (received,total){
var percentage = (received * 100) / total;
console.log(percentage + "% | " + received + " bytes out of " + total + " bytes.");
}
}).then(function(){
alert("File succesfully downloaded");
});
Have fun