Release 4.0.1
[DeezloaderRemix.git] / app / app.js
1 /*
2  *  _____                    _                    _
3  * |  __ \                  | |                  | |
4  * | |  | |  ___   ___  ____| |  ___    __ _   __| |  ___  _ __
5  * | |  | | / _ \ / _ \|_  /| | / _ \  / _` | / _` | / _ \| '__|
6  * | |__| ||  __/|  __/ / / | || (_) || (_| || (_| ||  __/| |
7  * |_____/  \___| \___|/___||_| \___/  \__,_| \__,_| \___||_|
8  *
9  *
10  *
11  *  Original work by ZzMTV <https://boerse.to/members/zzmtv.3378614/>
12  * */
13
14 const express = require('express');
15 const app = express();
16 const server = require('http').createServer(app);
17 const mflac = require('flac-metadata');
18 const io = require('socket.io').listen(server, {log: false});
19 const fs = require('fs-extra');
20 const async = require('async');
21 const request = require('requestretry').defaults({maxAttempts: 2147483647, retryDelay: 1000, timeout: 8000});
22 const os = require('os');
23 const ID3Writer = require('./lib/browser-id3-writer');
24 const Deezer = require('./deezer-api');
25 const path = require('path');
26 const crypto = require('crypto');
27 const logger = require('./logger.js');
28 const Spotify = require('spotify-web-api-node');
29 const authCredentials = require('./authCredentials.js')
30
31 // Load Config File
32 var userdata = "";
33 var homedata = "";
34 if(process.env.APPDATA){
35         userdata = process.env.APPDATA + path.sep + "Deezloader Remix\\";
36         homedata = os.homedir();
37 }else if(process.platform == "darwin"){
38         homedata = os.homedir();
39         userdata = homedata + '/Library/Application Support/Deezloader Remix/';
40 }else if(process.platform == "android"){
41         homedata = os.homedir() + "/storage/shared";
42         userdata = homedata + "/Deezloader Remix/";
43 }else{
44         homedata = os.homedir();
45         userdata = homedata + '/.config/Deezloader Remix/';
46 }
47
48 if(!fs.existsSync(userdata+"config.json")){
49         fs.outputFileSync(userdata+"config.json",fs.readFileSync(__dirname+path.sep+"default.json",'utf8'));
50 }
51
52 var spotifyApi = new Spotify(authCredentials);
53
54 // Settings update fix
55 let configFile = require(userdata+path.sep+"config.json");
56 if( typeof configFile.userDefined.numplaylistbyalbum != "boolean" ||
57         typeof configFile.userDefined.syncedlyrics != "boolean" ||
58         typeof configFile.userDefined.padtrck != "boolean" ||
59         typeof configFile.userDefined.extendedTags != "boolean"||
60         typeof configFile.userDefined.partOfSet != "boolean"||
61         typeof configFile.userDefined.chartsCountry != "string"||
62         typeof configFile.userDefined.albumNameTemplate != "string"){
63                 fs.outputFileSync(userdata+"config.json",fs.readFileSync(__dirname+path.sep+"default.json",'utf8'));
64                 configFile = require(userdata+path.sep+"config.json");
65 }
66
67 // Main Constants
68 const configFileLocation = userdata+"config.json";
69 const autologinLocation = userdata+"autologin";
70 const coverArtFolder = os.tmpdir() + path.sep + 'deezloader-imgs' + path.sep;
71 const defaultDownloadDir = homedata + path.sep + "Music" + path.sep + 'Deezloader' + path.sep;
72 const defaultSettings = require('./default.json').userDefined;
73
74 // Setup the folders START
75 let mainFolder = defaultDownloadDir;
76
77 if (configFile.userDefined.downloadLocation != null) {
78         mainFolder = configFile.userDefined.downloadLocation;
79 }
80
81 initFolders();
82 // END
83
84 // Route and Create server
85 app.use('/', express.static(__dirname + '/public/'));
86 server.listen(configFile.serverPort);
87 logger.logs('Info', 'Server is running @ localhost:' + configFile.serverPort);
88
89 //Autologin encryption/decryption
90 var ekey = "62I9smDurjvfOdn2JhUdi99yeoAhxikw";
91
92 function alencrypt(input) {
93         var iv = crypto.randomBytes(16);
94         var data = new Buffer(input).toString('binary');
95         key = new Buffer(ekey, "utf8");
96         var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
97         var encrypted;
98         encrypted =  cipher.update(data, 'utf8', 'binary') +  cipher.final('binary');
99         var encoded = new Buffer(iv, 'binary').toString('hex') + new Buffer(encrypted, 'binary').toString('hex');
100
101         return encoded;
102 }
103
104 function aldecrypt(encoded) {
105         var combined = new Buffer(encoded, 'hex');
106         key = new Buffer(ekey, "utf8");
107         // Create iv
108         var iv = new Buffer(16);
109         combined.copy(iv, 0, 0, 16);
110         edata = combined.slice(16).toString('binary');
111         // Decipher encrypted data
112         var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
113         var decrypted, plaintext;
114         plaintext = (decipher.update(edata, 'binary', 'utf8') + decipher.final('utf8'));
115
116         return plaintext;
117 }
118
119 // START sockets clusterfuck
120 io.sockets.on('connection', function (socket) {
121         socket.downloadQueue = [];
122         socket.currentItem = null;
123         socket.lastQueueId = null;
124
125         socket.on("login", function (username, password, autologin) {
126                 Deezer.init(username, password, function (err) {
127                         if(err){
128                                 socket.emit("login", err.message);
129                                 logger.logs('Error',"Failed to login, "+err.message);
130                         }else{
131                                 if(autologin){
132                                         var data = username + "\n" + password;
133                                         fs.outputFile(autologinLocation, alencrypt(data) , function(){
134                                                 if(!err){
135                                                         logger.logs('Info',"Added autologin successfully");
136                                                 }else{
137                                                         logger.logs('Info',"Failed to add autologin file");
138                                                 }
139                                         });
140                                 }
141                                 socket.emit("login", "none");
142                                 logger.logs('Info',"Logged in successfully");
143                         }
144                 });
145         });
146
147         socket.on("autologin", function(){
148                 fs.readFile(autologinLocation, function(err, data){
149                         if(err){
150                                 logger.logs('Info',"No auto login found");
151                                 return;
152                         }
153                         try{
154                                 var fdata = aldecrypt(data.toString('utf8'));
155
156                         }catch(e){
157                                 logger.logs('Warning',"Invalid autologin file, deleting");
158                                 fs.unlink(autologinLocation,function(){
159                                 });
160                                 return;
161                         }
162                         fdata = fdata.split('\n');
163                         socket.emit("autologin",fdata[0],fdata[1]);
164                 });
165         });
166
167         socket.on("logout", function(){
168                 logger.logs('Info',"Logged out");
169                 fs.unlink(autologinLocation,function(){
170                 });
171                 return;
172         });
173
174         Deezer.onDownloadProgress = function (track, progress) {
175                 if (!track.trackSocket) {
176                         return;
177                 }
178
179                 if(track.trackSocket.currentItem.type == "track"){
180                         let complete;
181                         if (!track.trackSocket.currentItem.percentage) {
182                                 track.trackSocket.currentItem.percentage = 0;
183                         }
184                         if(configFile.userDefined.hifi){
185                                 complete = track.FILESIZE_FLAC;
186                         }else{
187                                 if (track.FILESIZE_MP3_320) {
188                                         complete = track.FILESIZE_MP3_320;
189                                 } else if (track.FILESIZE_MP3_256) {
190                                         complete = track.FILESIZE_MP3_256;
191                                 } else {
192                                         complete = track.FILESIZE_MP3_128 || 0;
193                                 }
194                         }
195
196                         let percentage = (progress / complete) * 100;
197
198                         if ((percentage - track.trackSocket.currentItem.percentage > 1) || (progress == complete)) {
199                                 track.trackSocket.currentItem.percentage = percentage;
200                                 track.trackSocket.emit("downloadProgress", {
201                                         queueId: track.trackSocket.currentItem.queueId,
202                                         percentage: track.trackSocket.currentItem.percentage
203                                 });
204                         }
205                 }
206         };
207
208         function addToQueue(object) {
209                 socket.downloadQueue.push(object);
210                 socket.emit('addToQueue', object);
211
212                 queueDownload(getNextDownload());
213         }
214
215         function getNextDownload() {
216                 if (socket.currentItem != null || socket.downloadQueue.length == 0) {
217                         if (socket.downloadQueue.length == 0 && socket.currentItem == null) {
218                                 socket.emit("emptyDownloadQueue", {});
219                         }
220                         return null;
221                 }
222                 socket.currentItem = socket.downloadQueue[0];
223                 return socket.currentItem;
224         }
225
226         //currentItem: the current item being downloaded at that moment such as a track or an album
227         //downloadQueue: the tracks in the queue to be downloaded
228         //lastQueueId: the most recent queueID
229         //queueId: random number generated when user clicks download on something
230         function queueDownload(downloading) {
231                 if (!downloading) return;
232
233                 // New batch emits new message
234                 if (socket.lastQueueId != downloading.queueId) {
235                         if (downloading.type != "spotifyplaylist"){
236                                 socket.emit("downloadStarted", {queueId: downloading.queueId});
237                         }
238                         socket.lastQueueId = downloading.queueId;
239                 }
240
241                 if (downloading.type == "track") {
242                         logger.logs('Info',"Registered a track "+downloading.id);
243                         downloadTrack([downloading.id,0], downloading.settings, null, function (err) {
244                                 if (err) {
245                                         downloading.failed++;
246                                 } else {
247                                         downloading.downloaded++;
248                                 }
249                                 socket.emit("updateQueue", downloading);
250                                 if (socket.downloadQueue[0] && (socket.downloadQueue[0].queueId == downloading.queueId)) {
251                                         socket.downloadQueue.shift();
252                                 }
253                                 socket.currentItem = null;
254                                 //fs.rmdirSync(coverArtDir);
255                                 queueDownload(getNextDownload());
256                         });
257                 } else if (downloading.type == "playlist") {
258                         logger.logs('Info',"Registered a playlist "+downloading.id);
259                         Deezer.getPlaylistTracks(downloading.id, function (tracks, err) {
260                                 downloading.settings.plName = downloading.name;
261                                 async.eachSeries(tracks.data, function (t, callback) {
262                                         if (downloading.cancelFlag) {
263                                                 logger.logs('Info',"Stopping the playlist queue");
264                                                 callback("stop");
265                                                 return;
266                                         }
267                                         downloading.settings.playlist = {
268                                                 position: tracks.data.indexOf(t),
269                                                 fullSize: tracks.data.length
270                                         };
271                                         downloadTrack([t.id,0], downloading.settings, null, function (err) {
272                                                 if (!err) {
273                                                         downloading.downloaded++;
274                                                 } else {
275                                                         downloading.failed++;
276                                                 }
277                                                 socket.emit("downloadProgress", {
278                                                         queueId: downloading.queueId,
279                                                         percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
280                                                 });
281                                                 socket.emit("updateQueue", downloading);
282                                                 callback();
283                                         });
284                                 }, function (err) {
285                                         logger.logs('Info',"Playlist finished "+downloading.name);
286                                         if(typeof socket.downloadQueue[0] != 'undefined'){
287                                                 socket.emit("downloadProgress", {
288                                                         queueId: socket.downloadQueue[0].queueId,
289                                                         percentage: 100
290                                                 });
291                                         }
292                                         if (downloading && socket.downloadQueue[0] && socket.downloadQueue[0].queueId == downloading.queueId) socket.downloadQueue.shift();
293                                         socket.currentItem = null;
294                                         //fs.rmdirSync(coverArtDir);
295                                         queueDownload(getNextDownload());
296                                 });
297                         });
298                 } else if (downloading.type == "spotifyplaylist") {
299                                 spotifyApi.clientCredentialsGrant().then(function(creds) {
300                                         downloading.settings.plName = downloading.name;
301                                         spotifyApi.setAccessToken(creds.body['access_token']);
302                                         numPages=Math.floor((downloading.size-1)/100);
303                                         let pages = []
304                                         downloading.playlistContent = new Array(downloading.size);
305                                         for (let offset = 0; offset<=numPages; offset++){
306                                                 pages.push(new Promise(function(resolvePage) {
307                                                         spotifyApi.getPlaylistTracks(downloading.settings.spotifyUser, downloading.id, {fields: "", offset: offset}).then(function(resp) {
308                                                                 resp.body['items'].forEach((t, index) => {
309                                                                         downloading.playlistContent[(offset*100)+index] = new Promise(function(resolve, reject) {
310                                                                                 Deezer.track2ID(t.track.artists[0].name, t.track.name, function (response,err){
311                                                                                         resolve([response,0]);
312                                                                                 });
313                                                                         });
314                                                                 });
315                                                                 logger.logs("Debug", "Page "+offset+" done");
316                                                                 resolvePage();
317                                                         }, function(err) {console.log('Something went wrong!', err)});
318                                                 }));
319                                         }
320                                         logger.logs("Info","Waiting for all pages");
321                                         Promise.all(pages).then((val)=>{
322                                                 logger.logs("Info","Waiting for all tracks to be converted");
323                                                 Promise.all(downloading.playlistContent).then((values)=>{
324                                                         logger.logs("Info","All tracks converted, starting download");
325                                                         socket.emit("downloadStarted", {queueId: downloading.queueId});
326                                                         async.eachSeries(values, function (t, callback) {
327                                                                 if (downloading.cancelFlag) {
328                                                                         logger.logs('Info',"Stopping the playlist queue");
329                                                                         callback("stop");
330                                                                         return;
331                                                                 }
332                                                                 downloading.settings.playlist = {
333                                                                         position: values.indexOf(t),
334                                                                         fullSize: values.length
335                                                                 };
336                                                                 downloadTrack(t, downloading.settings, null, function (err) {
337                                                                         if (!err) {
338                                                                                 downloading.downloaded++;
339                                                                         } else {
340                                                                                 downloading.failed++;
341                                                                         }
342                                                                         socket.emit("downloadProgress", {
343                                                                                 queueId: downloading.queueId,
344                                                                                 percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
345                                                                         });
346                                                                         socket.emit("updateQueue", downloading);
347                                                                         callback();
348                                                                 });
349                                                         }, function (err) {
350                                                                 logger.logs('Info',"Playlist finished "+downloading.name);
351                                                                 if(typeof socket.downloadQueue[0] != 'undefined'){
352                                                                         socket.emit("downloadProgress", {
353                                                                                 queueId: socket.downloadQueue[0].queueId,
354                                                                                 percentage: 100
355                                                                         });
356                                                                 }
357                                                                 if (downloading && socket.downloadQueue[0] && socket.downloadQueue[0].queueId == downloading.queueId) socket.downloadQueue.shift();
358                                                                 socket.currentItem = null;
359                                                                 //fs.rmdirSync(coverArtDir);
360                                                                 queueDownload(getNextDownload());
361                                                         });
362                                                 }).catch((err)=>{
363                                                         console.log('Something went wrong!', err);
364                                                 });
365                                         }).catch((err)=>{
366                                                 console.log('Something went wrong!', err);
367                                         });
368                                 }, function(err) {console.log('Something went wrong!', err)});
369                 } else if (downloading.type == "album") {
370                         logger.logs('Info',"Registered an album "+downloading.id);
371                         Deezer.getAlbumTracks(downloading.id, function (tracks, err) {
372                                 downloading.settings.tagPosition = true;
373                                 downloading.settings.albName = downloading.name;
374                                 downloading.settings.artName = downloading.artist;
375                                 async.eachSeries(tracks.data, function (t, callback) {
376                                         if (downloading.cancelFlag) {
377                                                 logger.logs('Info',"Stopping the album queue");
378                                                 callback("stop");
379                                                 return;
380                                         }
381                                         downloading.settings.playlist = {
382                                                 position: tracks.data.indexOf(t),
383                                                 fullSize: tracks.data.length
384                                         };
385                                         downloadTrack([t.id,0], downloading.settings, null, function (err) {
386                                                 if (!err) {
387                                                         downloading.downloaded++;
388                                                 } else {
389                                                         downloading.failed++;
390                                                 }
391                                                 socket.emit("downloadProgress", {
392                                                         queueId: downloading.queueId,
393                                                         percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
394                                                 });
395                                                 socket.emit("updateQueue", downloading);
396                                                 callback();
397                                         });
398                                 }, function (err) {
399                                         if (downloading.countPerAlbum) {
400                                                 if (socket.downloadQueue.length > 1 && socket.downloadQueue[1].queueId == downloading.queueId) {
401                                                         socket.downloadQueue[1].download = downloading.downloaded;
402                                                 }
403                                                 socket.emit("updateQueue", downloading);
404                                         }
405                                         logger.logs('Info',"Album finished "+downloading.name);
406                                         if(typeof socket.downloadQueue[0] != 'undefined'){
407                                                 socket.emit("downloadProgress", {
408                                                         queueId: socket.downloadQueue[0].queueId,
409                                                         percentage: 100
410                                                 });
411                                         }
412                                         if (downloading && socket.downloadQueue[0] && socket.downloadQueue[0].queueId == downloading.queueId) socket.downloadQueue.shift();
413                                         socket.currentItem = null;
414                                         queueDownload(getNextDownload());
415                                 });
416                         });
417                 }
418         }
419
420         socket.on("downloadtrack", function (data) {
421                 Deezer.getTrack(data.id, configFile.userDefined.hifi, function (track, err) {
422                         if (err) {
423                                 return;
424                         }
425                         let queueId = "id" + Math.random().toString(36).substring(2);
426                         let _track = {
427                                 name: track["SNG_TITLE"],
428                                 size: 1,
429                                 downloaded: 0,
430                                 failed: 0,
431                                 queueId: queueId,
432                                 id: track["SNG_ID"],
433                                 type: "track"
434                         };
435                         if (track["VERSION"]) _track.name = _track.name + " " + track["VERSION"];
436                         _track.settings = data.settings || {};
437                         addToQueue(_track);
438                 });
439         });
440
441         socket.on("downloadplaylist", function (data) {
442                 Deezer.getPlaylist(data.id, function (playlist, err) {
443                         if (err) {
444                                 return;
445                         }
446                         Deezer.getPlaylistSize(data.id, function (size, err) {
447                                 if (err) {
448                                         return;
449                                 }
450                                 let queueId = "id" + Math.random().toString(36).substring(2);
451                                 let _playlist = {
452                                         name: playlist["title"],
453                                         size: size,
454                                         downloaded: 0,
455                                         failed: 0,
456                                         queueId: queueId,
457                                         id: playlist["id"],
458                                         type: "playlist"
459                                 };
460                                 _playlist.settings = data.settings || {};
461                                 addToQueue(_playlist);
462                         });
463                 });
464         });
465
466         socket.on("downloadspotifyplaylist", function (data) {
467                 spotifyApi.clientCredentialsGrant().then(function(creds) {
468                         spotifyApi.setAccessToken(creds.body['access_token']);
469                         spotifyApi.getPlaylist(data.settings.spotifyUser, data.id, {fields: "id,name,tracks.total"}).then(function(resp) {
470                                 let queueId = "id" + Math.random().toString(36).substring(2);
471                                 let _playlist = {
472                                         name: resp.body["name"],
473                                         size: resp.body["tracks"]["total"],
474                                         downloaded: 0,
475                                         failed: 0,
476                                         queueId: queueId,
477                                         id: resp.body["id"],
478                                         type: "spotifyplaylist"
479                                 };
480                                 _playlist.settings = data.settings || {};
481                                 addToQueue(_playlist);
482                         }, function(err) {
483                                 console.log('Something went wrong!', err);
484                         });
485                 },
486                 function(err) {
487                         console.log('Something went wrong when retrieving an access token', err);
488                 });
489         });
490
491         socket.on("downloadalbum", function (data) {
492                 Deezer.getAlbum(data.id, function (album, err) {
493                         if (err) {
494                                 return;
495                         }
496                         Deezer.getAlbumSize(data.id, function (size, err) {
497                                 if (err) {
498                                         return;
499                                 }
500                                 let queueId = "id" + Math.random().toString(36).substring(2);
501                                 let _album = {
502                                         name: album["title"],
503                                         label: album["label"],
504                                         artist: album["artist"].name,
505                                         size: size,
506                                         downloaded: 0,
507                                         failed: 0,
508                                         queueId: queueId,
509                                         id: album["id"],
510                                         type: "album"
511                                 };
512                                 _album.settings = data.settings || {};
513                                 addToQueue(_album);
514                         });
515                 });
516         });
517
518         socket.on("downloadartist", function (data) {
519                 Deezer.getArtist(data.id, function (artist, err) {
520                         if (err) {
521                                 return;
522                         }
523                         Deezer.getArtistAlbums(data.id, function (albums, err) {
524                                 if (err) {
525                                         return;
526                                 }
527                                 for (let i = 0; i < albums.data.length; i++) {
528                                         Deezer.getAlbumSize(albums.data[i].id, function(size, err){
529                                                 if(err) {
530                                                   return;
531                                                 }
532                                                 let queueId = "id" + Math.random().toString(36).substring(2);
533                                                 let album = albums.data[i];
534                                                 let _album = {
535                                                         name: album["title"],
536                                                         artist: artist.name,
537                                                         size: size,
538                                                         downloaded: 0,
539                                                         failed: 0,
540                                                         queueId: queueId,
541                                                         id: album["id"],
542                                                         type: "album",
543                                                         countPerAlbum: true
544                                                 };
545                                                 _album.settings = data.settings || {};
546                                                 addToQueue(_album);
547                                         });
548                                 }
549                         });
550                 });
551         });
552
553         socket.on("getChartsTopCountry", function () {
554                 Deezer.getChartsTopCountry(function (charts, err) {
555                         if(err){
556                                 return;
557                         }
558                         if(charts){
559                                 charts = charts.data || [];
560                         }else{
561                                 charts = [];
562                         }
563                         socket.emit("getChartsTopCountry", {charts: charts.data, err: err});
564                 });
565         });
566
567         socket.on("getChartsCountryList", function (data) {
568                 Deezer.getChartsTopCountry(function (charts, err) {
569                         if(err){
570                                 return;
571                         }
572                         if(charts){
573                                 charts = charts.data || [];
574                         }else{
575                                 charts = [];
576                         }
577                         let countries = [];
578                         for (let i = 0; i < charts.length; i++) {
579                                 let obj = {
580                                         country: charts[i].title.replace("Top ", ""),
581                                         picture_small: charts[i].picture_small,
582                                         picture_medium: charts[i].picture_medium,
583                                         picture_big: charts[i].picture_big
584                                 };
585                                 countries.push(obj);
586                         }
587                         socket.emit("getChartsCountryList", {countries: countries, selected: data.selected});
588                 });
589         });
590
591         socket.on("getChartsTrackListByCountry", function (data) {
592                 if (!data.country) {
593                         socket.emit("getChartsTrackListByCountry", {err: "No country passed"});
594                         return;
595                 }
596
597                 Deezer.getChartsTopCountry(function (charts, err) {
598                         if(err){
599                                 return;
600                         }
601                         if(charts){
602                                 charts = charts.data || [];
603                         }else{
604                                 charts = [];
605                         }
606                         let countries = [];
607                         for (let i = 0; i < charts.length; i++) {
608                                 countries.push(charts[i].title.replace("Top ", ""));
609                         }
610
611                         if (countries.indexOf(data.country) == -1) {
612                                 socket.emit("getChartsTrackListByCountry", {err: "Country not found"});
613                                 return;
614                         }
615
616                         let playlistId = charts[countries.indexOf(data.country)].id;
617
618                         Deezer.getPlaylistTracks(playlistId, function (tracks, err) {
619                                 if (err) {
620                                         socket.emit("getChartsTrackListByCountry", {err: err});
621                                         return;
622                                 }
623                                 socket.emit("getChartsTrackListByCountry", {
624                                         playlist: charts[countries.indexOf(data.country)],
625                                         tracks: tracks.data
626                                 });
627                         });
628                 });
629         });
630
631         socket.on("search", function (data) {
632                 data.type = data.type || "track";
633                 if (["track", "playlist", "album", "artist"].indexOf(data.type) == -1) {
634                         data.type = "track";
635                 }
636
637                 // Remove "feat."  "ft." and "&" (causes only problems)
638                 data.text = data.text.replace(/ feat[\.]? /g, " ").replace(/ ft[\.]? /g, " ").replace(/\(feat[\.]? /g, " ").replace(/\(ft[\.]? /g, " ").replace(/\&/g, "");
639
640                 Deezer.search(encodeURIComponent(data.text), data.type, function (searchObject, err) {
641                         try {
642                                 socket.emit("search", {type: data.type, items: searchObject.data});
643                         } catch (e) {
644                                 socket.emit("search", {type: data.type, items: []});
645                         }
646                 });
647         });
648
649         socket.on("getInformation", function (data) {
650                 if (!data.type || (["track", "playlist", "album", "artist"].indexOf(data.type) == -1) || !data.id) {
651                         socket.emit("getInformation", {err: -1, response: {}, id: data.id});
652                         return;
653                 }
654
655                 let reqType = data.type.charAt(0).toUpperCase() + data.type.slice(1);
656
657                 Deezer["get" + reqType](data.id, function (response, err) {
658                         if (err) {
659                                 socket.emit("getInformation", {err: "wrong id", response: {}, id: data.id});
660                                 return;
661                         }
662                         socket.emit("getInformation", {response: response, id: data.id});
663                 });
664         });
665
666         socket.on("getTrackList", function (data) {
667                 if (!data.type || (["playlist", "album", "artist"].indexOf(data.type) == -1) || !data.id) {
668                         socket.emit("getTrackList", {err: -1, response: {}, id: data.id, reqType: data.type});
669                         return;
670                 }
671
672                 if (data.type == 'artist') {
673                         Deezer.getArtistAlbums(data.id, function (response, err) {
674                                 if (err) {
675                                         socket.emit("getTrackList", {err: "wrong id", response: {}, id: data.id, reqType: data.type});
676                                         return;
677                                 }
678                                 socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
679                         });
680                 } else {
681                         let reqType = data.type.charAt(0).toUpperCase() + data.type.slice(1);
682
683                         Deezer["get" + reqType + "Tracks"](data.id, function (response, err) {
684                                 if (err) {
685                                         socket.emit("getTrackList", {err: "wrong id", response: {}, id: data.id, reqType: data.type});
686                                         return;
687                                 }
688                                 socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
689                         });
690                 }
691
692         });
693
694         socket.on("cancelDownload", function (data) {
695                 if (!data.queueId) {
696                         return;
697                 }
698
699                 let cancel = false;
700                 let cancelSuccess;
701
702                 for (let i = 0; i < socket.downloadQueue.length; i++) {
703                         if (data.queueId == socket.downloadQueue[i].queueId) {
704                                 socket.downloadQueue.splice(i, 1);
705                                 i--;
706                                 cancel = true;
707                         }
708                 }
709
710                 if (socket.currentItem && socket.currentItem.queueId == data.queueId) {
711                         cancelSuccess = Deezer.cancelDecryptTrack();
712                         cancel = cancel || cancelSuccess;
713                 }
714
715
716                 if (cancelSuccess && socket.currentItem) {
717                         socket.currentItem.cancelFlag = true;
718                 }
719                 if (cancel) {
720                         socket.emit("cancelDownload", {queueId: data.queueId});
721                 }
722         });
723
724         socket.on("downloadAlreadyInQueue", function (data) {
725                 if (data.id) {
726                         return;
727                 }
728                 let isInQueue = checkIfAlreadyInQueue(data.id);
729                 if (isInQueue) {
730                         socket.emit("downloadAlreadyInQueue", {alreadyInQueue: true, id: data.id, queueId: isInQueue});
731                 } else {
732                         socket.emit("downloadAlreadyInQueue", {alreadyInQueue: false, id: data.id});
733                 }
734         });
735
736         socket.on("getUserSettings", function () {
737                 let settings = configFile.userDefined;
738                 if (!settings.downloadLocation) {
739                         settings.downloadLocation = mainFolder;
740                 }
741
742                 socket.emit('getUserSettings', {settings: settings});
743         });
744
745         socket.on("saveSettings", function (settings) {
746                 if (settings.userDefined.downloadLocation == defaultDownloadDir) {
747                         settings.userDefined.downloadLocation = null;
748                 } else {
749                         settings.userDefined.downloadLocation = path.resolve(settings.userDefined.downloadLocation + path.sep) + path.sep;
750                         mainFolder = settings.userDefined.downloadLocation;
751                 }
752
753                 configFile.userDefined = settings.userDefined;
754                 fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
755                         if (err) return;
756                         logger.logs('Info',"Settings updated");
757                         initFolders();
758                 });
759         });
760
761         function downloadTrack(id, settings, altmetadata, callback) {
762                 logger.logs('Info',"Getting track data");
763                 Deezer.getTrack(id[0], configFile.userDefined.hifi, function (track, err) {
764                         if (err) {
765                                 if(id[1] != 0){
766                                         logger.logs('Warning',"Failed to download track, falling on alternative");
767                                         downloadTrack([id[1],0], settings, null, function(err){
768                                                 callback(err);
769                                         });
770                                 }else{
771                                         logger.logs('Error',"Failed to download track");
772                                         callback(err);
773                                 }
774                                 return;
775                         }
776                         logger.logs('Info',"Getting album data");
777                         Deezer.getAlbum(track["ALB_ID"], function(res, err){
778                                 if(err){
779                                         if(id[1] != 0){
780                                                 logger.logs('Warning',"Failed to download track, falling on alternative");
781                                                 downloadTrack([id[1],0], settings, null, function(err){
782                                                         callback(err);
783                                                 });
784                                         }else{
785                                                 logger.logs('Error',"Failed to download track");
786                                                 callback(new Error("Album does not exists."));
787                                         }
788                                         return;
789                                 }
790                                 logger.logs('Info',"Getting ATrack data");
791                                 Deezer.getATrack(res.tracks.data[res.tracks.data.length - 1].id, function(tres){
792                                         track.trackSocket = socket;
793
794                                         settings = settings || {};
795                                         // winston.log('debug', 'TRACK:', track);
796                                         if (track["VERSION"]) track["SNG_TITLE"] += " " + track["VERSION"];
797                                         var ajson = res;
798                                         var tjson = tres;
799                                         if(track["SNG_CONTRIBUTORS"]){
800                                                 if(track["SNG_CONTRIBUTORS"].composer){
801                                                         var composertag = "";
802                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].composer.length; i++) {
803                                                                 composertag += track["SNG_CONTRIBUTORS"].composer[i] + ", ";
804                                                         }
805                                                         composertag = composertag.substring(0,composertag.length-2);
806                                                 }
807                                                 if(track["SNG_CONTRIBUTORS"].musicpublisher){
808                                                         var publishertag = "";
809                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].musicpublisher.length; i++) {
810                                                                 publishertag += track["SNG_CONTRIBUTORS"].musicpublisher[i] + ", ";
811                                                         }
812                                                         publishertag = publishertag.substring(0,publishertag.length-2);
813                                                 }
814                                                 if(track["SNG_CONTRIBUTORS"].producer){
815                                                         var producertag = "";
816                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].producer.length; i++) {
817                                                                 producertag += track["SNG_CONTRIBUTORS"].producer[i] + ", ";
818                                                         }
819                                                         producertag = producertag.substring(0,producertag.length-2);
820                                                 }
821                                                 if(track["SNG_CONTRIBUTORS"].engineer){
822                                                         var engineertag = "";
823                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].engineer.length; i++) {
824                                                                 engineertag += track["SNG_CONTRIBUTORS"].engineer[i] + ", ";
825                                                         }
826                                                         engineertag = engineertag.substring(0,engineertag.length-2);
827                                                 }
828                                                 if(track["SNG_CONTRIBUTORS"].writer){
829                                                         var writertag = "";
830                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].writer.length; i++) {
831                                                                 writertag += track["SNG_CONTRIBUTORS"].writer[i] + ", ";
832                                                         }
833                                                         writertag = writertag.substring(0,writertag.length-2);
834                                                 }
835                                                 if(track["SNG_CONTRIBUTORS"].author){
836                                                         var authortag = "";
837                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].author.length; i++) {
838                                                                 authortag += track["SNG_CONTRIBUTORS"].author[i] + ", ";
839                                                         }
840                                                         authortag = authortag.substring(0,authortag.length-2);
841                                                 }
842                                                 if(track["SNG_CONTRIBUTORS"].mixer){
843                                                         var mixertag = "";
844                                                         for (var i = 0; i < track["SNG_CONTRIBUTORS"].mixer.length; i++) {
845                                                                 mixertag += track["SNG_CONTRIBUTORS"].mixer[i] + ", ";
846                                                         }
847                                                         mixertag = mixertag.substring(0,mixertag.length-2);
848                                                 }
849                                         }
850                                         let metadata;
851                                         if(altmetadata){
852                                                 metadata = altmetadata;
853                                                 if(track["LYRICS_TEXT"] && !metadata.unsynchronisedLyrics){
854                                                         metadata.unsynchronisedLyrics = {
855                                                                 description: "",
856                                                                 lyrics: track["LYRICS_TEXT"]
857                                                         };
858                                                 }
859                                         }else{
860                                                 metadata = {
861                                                         title: track["SNG_TITLE"],
862                                                         artist: track["ART_NAME"],
863                                                         album: track["ALB_TITLE"],
864                                                         performerInfo: ajson.artist.name,
865                                                         trackNumber: track["TRACK_NUMBER"] + "/" + ajson.nb_tracks,
866                                                         partOfSet: track["DISK_NUMBER"] + "/" + tjson.disk_number,
867                                                         explicit: track["EXPLICIT_LYRICS"],
868                                                         ISRC: track["ISRC"],
869                                                 };
870                                                 if (configFile.userDefined.extendedTags){
871                                                         metadata.push({
872                                                                 length: track["DURATION"],
873                                                                 BARCODE: ajson.upc,
874                                                                 rtype: ajson.record_type
875                                                         });
876                                                         if(track["COPYRIGHT"]){
877                                                                 metadata.copyright = track["COPYRIGHT"];
878                                                         }
879                                                         if(composertag){
880                                                                 metadata.composer = composertag;
881                                                         }
882                                                         if(mixertag){
883                                                                 metadata.mixer = mixertag;
884                                                         }
885                                                         if(authortag){
886                                                                 metadata.author = authortag;
887                                                         }
888                                                         if(writertag){
889                                                                 metadata.writer = writertag;
890                                                         }
891                                                         if(engineertag){
892                                                                 metadata.engineer = engineertag;
893                                                         }
894                                                         if(producertag){
895                                                                 metadata.producer = producertag;
896                                                         }
897                                                         if(track["LYRICS_TEXT"]){
898                                                                 metadata.unsynchronisedLyrics = {
899                                                                         description: "",
900                                                                         lyrics: track["LYRICS_TEXT"]
901                                                                 };
902                                                         }
903                                                         if (track["GAIN"]) {
904                                                                 metadata.trackgain = track["GAIN"];
905                                                         }
906                                                 }
907
908
909                                                 if(ajson.label){
910                                                         metadata.publisher = ajson.label;
911                                                 }
912                                                 if(settings.plName && !(settings.createArtistFolder || settings.createAlbumFolder) && !configFile.userDefined.numplaylistbyalbum){
913                                                         metadata.trackNumber = (parseInt(settings.playlist.position)+1).toString() + "/" + settings.playlist.fullSize;
914                                                         metadata.partOfSet = "1/1";
915                                                 }
916                                                 if(settings.artName){
917                                                         metadata.trackNumber = (settings.playlist.position+1).toString() + "/" + ajson.nb_tracks;
918                                                 }
919                                                 if (0 < parseInt(track["BPM"])) {
920                                                         metadata.bpm = track["BPM"];
921                                                 }
922                                                 if(ajson.genres && ajson.genres.data[0] && ajson.genres.data[0].name){
923                                                         metadata.genre = ajson.genres.data[0].name;
924                                                     if (track.format == 9){
925                                                             metadata.genre = ajson.genres.data[0].name;
926                                                     } else {
927                                                         genreArray = [];
928                                                         var first = true;
929                                                         ajson.genres.data.forEach(function(genre){
930                                                                 genreArray.push(genre.name);
931                                                         });
932                                                         Array.from(new Set(genreArray)).forEach(function(genre){
933                                                                 if(first){
934                                                                         metadata.genre = genre;
935                                                                         first = false;
936                                                                 } else{
937                                                                         if(metadata.genre.indexOf(genre) == -1)
938                                                                                 metadata.genre += String.fromCharCode(parseInt("\u0000",16)) + genre;
939                                                                 }
940                                                         });
941                                                 }
942                                                 }
943                                                 if (track["ALB_PICTURE"]) {
944                                                         metadata.image = Deezer.albumPicturesHost + track["ALB_PICTURE"] + settings.artworkSize;
945                                                 }
946
947                                                 if (ajson.release_date) {
948                                                         metadata.year = ajson.release_date.slice(0, 4);
949                                                         metadata.date = ajson.release_date;
950                                                 }else if(track["PHYSICAL_RELEASE_DATE"]){
951                                                         metadata.year = track["PHYSICAL_RELEASE_DATE"].slice(0, 4);
952                                                         metadata.date = track["PHYSICAL_RELEASE_DATE"];
953                                                 }
954                                         }
955                                         let filename = fixName(`${metadata.artist} - ${metadata.title}`);
956                                         if (settings.filename) {
957                                                 filename = fixName(settingsRegex(metadata, settings.filename, settings.playlist));
958                                         }
959
960                                         let filepath = mainFolder;
961                                         if (settings.createArtistFolder || settings.createAlbumFolder) {
962                                                 if(settings.plName){
963                                                         filepath += antiDot(fixName(settings.plName)) + path.sep;
964                                                 }
965                                                 if (settings.createArtistFolder) {
966                                                         if(settings.artName){
967                                                                 filepath += antiDot(fixName(settings.artName)) + path.sep;
968                                                         }else{
969                                                                 filepath += antiDot(fixName(metadata.artist)) + path.sep;
970                                                         }
971                                                 }
972
973                                                 if (settings.createAlbumFolder) {
974                                                         if(settings.artName){
975                                                                 filepath += antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,settings.artName,settings.albName))) + path.sep;
976                                                         }else{
977                                                                 filepath += antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,metadata.performerInfo,metadata.album))) + path.sep;
978                                                         }
979                                                 }
980                                         } else if (settings.plName) {
981                                                 filepath += antiDot(fixName(settings.plName)) + path.sep;
982                                         } else if (settings.artName) {
983                                                 filepath += antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,settings.artName,settings.albName))) + path.sep;
984                                         }
985
986                                         let writePath;
987                                         if(track.format == 9){
988                                                 writePath = filepath + filename + '.flac';
989                                         }else{
990                                                 writePath = filepath + filename + '.mp3';
991                                         }
992                                         if(track["LYRICS_SYNC_JSON"] && configFile.userDefined.syncedlyrics){
993                                                 var lyricsbuffer = "";
994                                                 for(var i=0;i<track["LYRICS_SYNC_JSON"].length;i++){
995                                                         if(track["LYRICS_SYNC_JSON"][i].lrc_timestamp){
996                                                                 lyricsbuffer += track["LYRICS_SYNC_JSON"][i].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
997                                                         }else if(i+1 < track["LYRICS_SYNC_JSON"].length){
998                                                                 lyricsbuffer += track["LYRICS_SYNC_JSON"][i+1].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
999                                                         }
1000                                                 }
1001                                                 if(track.format == 9){
1002                                                         fs.outputFile(writePath.substring(0,writePath.length-5)+".lrc",lyricsbuffer,function(){});
1003                                                 }else{
1004                                                         fs.outputFile(writePath.substring(0,writePath.length-4)+".lrc",lyricsbuffer,function(){});
1005                                                 }
1006                                         }
1007                                         logger.logs('Info','Downloading file to ' + writePath);
1008                                         if (fs.existsSync(writePath)) {
1009                                                 logger.logs('Info',"Already downloaded: " + metadata.artist + ' - ' + metadata.title);
1010                                                 callback();
1011                                                 return;
1012                                         }
1013
1014                                         //Get image
1015                                         if (metadata.image) {
1016                                                 let imgPath;
1017                                                 //If its not from an album but a playlist.
1018                                                 if(!settings.tagPosition && !settings.createAlbumFolder){
1019                                                         imgPath = coverArtFolder + fixName(metadata.ISRC) + ".jpg";
1020                                                 }else{
1021                                                         imgPath = filepath + "folder.jpg";
1022                                                 }
1023                                                 if(fs.existsSync(imgPath) && !imgPath.includes(coverArtFolder)){
1024                                                         metadata.imagePath = (imgPath).replace(/\\/g, "/");
1025                                                         logger.logs('Info',"Starting the download process CODE:1");
1026                                                         condownload();
1027                                                 }else{
1028                                                         request.get(metadata.image, {encoding: 'binary'}, function(error,response,body){
1029                                                                 if(error){
1030                                                                         logger.logs('Error', error.stack);
1031                                                                         metadata.image = undefined;
1032                                                                         metadata.imagePath = undefined;
1033                                                                         return;
1034                                                                 }
1035                                                                 fs.outputFile(imgPath,body,'binary',function(err){
1036                                                                         if(err){
1037                                                                                 logger.logs('Error', err.stack);
1038                                                                         metadata.image = undefined;
1039                                                                         metadata.imagePath = undefined;
1040                                                                                 return;
1041                                                                         }
1042                                                                         metadata.imagePath = (imgPath).replace(/\\/g, "/");
1043                                                                         logger.logs('Info',"Starting the download process CODE:2");
1044                                                                         condownload();
1045                                                                 })
1046                                                         });
1047                                                 }
1048                                         }else{
1049                                                 metadata.image = undefined;
1050                                                 logger.logs('Info',"Starting the download process CODE:3");
1051                                                 condownload();
1052                                         }
1053                                         function condownload(){
1054                                                 var tempPath = writePath+".temp";
1055                                                 logger.logs('Info',"Downloading and decrypting");
1056                                                 Deezer.decryptTrack(tempPath,track, function (err) {
1057                                                         if (err && err.message == "aborted") {
1058                                                                 socket.currentItem.cancelFlag = true;
1059                                                                 logger.logs('Info',"Track got aborted");
1060                                                                 callback();
1061                                                                 return;
1062                                                         }
1063                                                         if (err) {
1064                                                                 Deezer.hasTrackAlternative(id[0], function (alternative, err) {
1065                                                                         if (err || !alternative) {
1066                                                                                 logger.logs('Error',"Failed to download: " + metadata.artist + " - " + metadata.title);
1067                                                                                 callback(err);
1068                                                                                 return;
1069                                                                         }
1070                                                                         logger.logs('Error',"Failed to download: " + metadata.artist + " - " + metadata.title+", falling on alternative");
1071                                                                         downloadTrack([alternative.SNG_ID,0], settings, metadata, callback);
1072                                                                 });
1073                                                                 return;
1074                                                         }
1075                                                         if (settings.createM3UFile && settings.playlist) {
1076                                                                 if(track.format == 9){
1077                                                                         fs.appendFileSync(filepath + "playlist.m3u", filename + ".flac\r\n");
1078                                                                 }else{
1079                                                                         fs.appendFileSync(filepath + "playlist.m3u", filename + ".mp3\r\n");
1080                                                                 }
1081                                                         }
1082                                                         logger.logs('Info',"Downloaded: " + metadata.artist + " - " + metadata.title);
1083                                                         metadata.artist = '';
1084                                                         var first = true;
1085                                                         artistArray = []
1086                                                         track['ARTISTS'].forEach(function(artist){
1087                                                                 artistArray.push(artist['ART_NAME']);
1088                                                         });
1089                                                         var separator = String.fromCharCode(parseInt("\u0000",16));
1090                                                         if (track.format == 9)
1091                                                             separator = ', ';
1092                                                         Array.from(new Set(artistArray)).forEach(function(artist){
1093                                                                 if(first){
1094                                                                         metadata.artist = artist;
1095                                                                         first = false;
1096                                                                 } else{
1097                                                                         if(metadata.artist.indexOf(artist) == -1)
1098                                                                                 metadata.artist += separator + artist;
1099                                                                 }
1100                                                         });
1101
1102                                                         if(track.format == 9){
1103                                                                 let flacComments = [
1104                                                                         'TITLE=' + metadata.title,
1105                                                                         'ALBUM=' + metadata.album,
1106                                                                         'ALBUMARTIST=' + metadata.performerInfo,
1107                                                                         'ARTIST=' + metadata.artist,
1108                                                                         'TRACKNUMBER=' + splitNumber(metadata.trackNumber,false),
1109                                                                         'DISCNUMBER=' + splitNumber(metadata.partOfSet,false),
1110                                                                         'TRACKTOTAL=' + splitNumber(metadata.trackNumber,true),
1111                                                                         'DISCTOTAL=' + splitNumber(metadata.partOfSet,true),
1112                                                                         'ITUNESADVISORY=' + metadata.explicit,
1113                                                                         'ISRC=' + metadata.ISRC
1114                                                                 ];
1115                                                                 if(configFile.userDefined.extendedTags){
1116                                                                         flacComments.push(
1117                                                                                 'LENGTH=' + metadata.length,
1118                                                                                 'BARCODE=' + metadata.BARCODE
1119                                                                         );
1120                                                                 }
1121                                                                 if(metadata.unsynchronisedLyrics){
1122                                                                         flacComments.push('LYRICS='+metadata.unsynchronisedLyrics.lyrics);
1123                                                                 }
1124                                                                 if(metadata.genre){
1125                                                                         flacComments.push('GENRE=' + metadata.genre);
1126                                                                 }
1127                                                                 if(metadata.copyright){
1128                                                                         flacComments.push('COPYRIGHT=' + metadata.copyright);
1129                                                                 }
1130                                                                 if (0 < parseInt(metadata.year)) {
1131                                                                         flacComments.push('DATE=' + metadata.date);
1132                                                                         flacComments.push('YEAR=' + metadata.year);
1133                                                                 }
1134                                                                 if (0 < parseInt(metadata.bpm)) {
1135                                                                         flacComments.push('BPM=' + metadata.bpm);
1136                                                                 }
1137                                                                 if(metadata.composer){
1138                                                                         flacComments.push('COMPOSER=' + metadata.composer);
1139                                                                 }
1140                                                                 if(metadata.publisher){
1141                                                                         flacComments.push('ORGANIZATION=' + metadata.publisher);
1142                                                                 }
1143                                                                 if(metadata.mixer){
1144                                                                         flacComments.push('MIXER=' + metadata.mixer);
1145                                                                 }
1146                                                                 if(metadata.author){
1147                                                                         flacComments.push('AUTHOR=' + metadata.author);
1148                                                                 }
1149                                                                 if(metadata.writer){
1150                                                                         flacComments.push('WRITER=' + metadata.writer);
1151                                                                 }
1152                                                                 if(metadata.engineer){
1153                                                                         flacComments.push('ENGINEER=' + metadata.engineer);
1154                                                                 }
1155                                                                 if(metadata.producer){
1156                                                                         flacComments.push('PRODUCER=' + metadata.producer);
1157                                                                 }
1158                                                                 if(metadata.trackgain){
1159                                                                         flacComments.push('REPLAYGAIN_TRACK_GAIN=' + metadata.trackgain);
1160                                                                 }
1161                                                                 const reader = fs.createReadStream(tempPath);
1162                                                                 const writer = fs.createWriteStream(writePath);
1163                                                                 let processor = new mflac.Processor({parseMetaDataBlocks: true});
1164
1165                                                                 let vendor = 'reference libFLAC 1.2.1 20070917';
1166                                                                 let cover = null;
1167                                                                 if(metadata.imagePath){
1168                                                                         cover = fs.readFileSync(metadata.imagePath);
1169                                                                 }
1170                                                                 let mdbVorbisPicture;
1171                                                                 let mdbVorbisComment;
1172                                                                 processor.on('preprocess', (mdb) => {
1173                                                                         // Remove existing VORBIS_COMMENT and PICTURE blocks, if any.
1174                                                                         if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type) {
1175                                                                                 mdb.remove();
1176                                                                         } else if (mflac.Processor.MDB_TYPE_PICTURE === mdb.type) {
1177                                                                                 mdb.remove();
1178                                                                         }
1179
1180                                                                         if (mdb.isLast) {
1181                                                                                 var res = 0;
1182                                                                                 if(configFile.userDefined.artworkSize.includes("1400")){
1183                                                                                         res = 1400;
1184                                                                                 }else if(configFile.userDefined.artworkSize.includes("1200")){
1185                                                                                         res = 1200;
1186                                                                                 }else if(configFile.userDefined.artworkSize.includes("1000")){
1187                                                                                         res = 1000;
1188                                                                                 }else if(configFile.userDefined.artworkSize.includes("800")){
1189                                                                                         res = 800;
1190                                                                                 }else if(configFile.userDefined.artworkSize.includes("500")){
1191                                                                                         res = 500;
1192                                                                                 }
1193                                                                                 if(cover){
1194                                                                                         mdbVorbisPicture = mflac.data.MetaDataBlockPicture.create(true, 3, 'image/jpeg', '', res, res, 24, 0, cover);
1195                                                                                 }
1196                                                                                 mdbVorbisComment = mflac.data.MetaDataBlockVorbisComment.create(false, vendor, flacComments);
1197                                                                                 mdb.isLast = false;
1198                                                                         }
1199                                                                 });
1200
1201                                                                 processor.on('postprocess', (mdb) => {
1202                                                                         if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type && null !== mdb.vendor) {
1203                                                                                 vendor = mdb.vendor;
1204                                                                         }
1205
1206                                                                         if (mdbVorbisPicture && mdbVorbisComment) {
1207                                                                                 processor.push(mdbVorbisComment.publish());
1208                                                                                 processor.push(mdbVorbisPicture.publish());
1209                                                                         }else if(mdbVorbisComment){
1210                                                                                 processor.push(mdbVorbisComment.publish());
1211                                                                         }
1212                                                                 });
1213
1214                                                                 reader.on('end', () => {
1215                                                                         fs.remove(tempPath);
1216                                                                 });
1217
1218                                                                 reader.pipe(processor).pipe(writer);
1219                                                         }else{
1220                                                                 const songBuffer = fs.readFileSync(tempPath);
1221                                                                 const writer = new ID3Writer(songBuffer);
1222                                                                 writer.setFrame('TIT2', metadata.title)
1223                                                                         .setFrame('TPE1', [metadata.artist])
1224                                                                         .setFrame('TALB', metadata.album)
1225                                                                         .setFrame('TPE2', metadata.performerInfo)
1226                                                                         .setFrame('TRCK', (configFile.userDefined.partOfSet ? metadata.trackNumber : splitNumber(metadata.trackNumber,false)))
1227                                                                         .setFrame('TPOS', (configFile.userDefined.partOfSet ? metadata.partOfSet : splitNumber(metadata.partOfSet,false)))
1228                                                                         .setFrame('TSRC', metadata.ISRC);
1229                                                                 if (configFile.userDefined.extendedTags){
1230                                                                         writer.setFrame('TLEN', metadata.length)
1231                                                                                 .setFrame('TXXX', {
1232                                                                                         description: 'BARCODE',
1233                                                                                         value: metadata.BARCODE
1234                                                                                 })
1235                                                                 }
1236                                                                 if(metadata.imagePath){
1237                                                                         const coverBuffer = fs.readFileSync(metadata.imagePath);
1238                                                                         writer.setFrame('APIC', {
1239                                                                                 type: 3,
1240                                                                                 data: coverBuffer,
1241                                                                                 description: ''
1242                                                                         });
1243                                                                 }
1244                                                                 if(metadata.unsynchronisedLyrics){
1245                                                                         writer.setFrame('USLT', metadata.unsynchronisedLyrics);
1246                                                                 }
1247                                                                 if(metadata.publisher){
1248                                                                         writer.setFrame('TPUB', metadata.publisher);
1249                                                                 }
1250                                                                 if(metadata.genre){
1251                                                                         writer.setFrame('TCON', [metadata.genre]);
1252                                                                 }
1253                                                                 if(metadata.copyright){
1254                                                                         writer.setFrame('TCOP', metadata.copyright);
1255                                                                 }
1256                                                                 if (0 < parseInt(metadata.year)) {
1257                                                                         writer.setFrame('TDAT', metadata.date);
1258                                                                         writer.setFrame('TYER', metadata.year);
1259                                                                 }
1260                                                                 if (0 < parseInt(metadata.bpm)) {
1261                                                                         writer.setFrame('TBPM', metadata.bpm);
1262                                                                 }
1263                                                                 if(metadata.composer){
1264                                                                         writer.setFrame('TCOM', [metadata.composer]);
1265                                                                 }
1266                                                                 if(metadata.trackgain){
1267                                                                         writer.setFrame('TXXX', {
1268                                                                                 description: 'REPLAYGAIN_TRACK_GAIN',
1269                                                                                 value: metadata.trackgain
1270                                                                         });
1271                                                                 }
1272                                                                 writer.addTag();
1273
1274                                                                 const taggedSongBuffer = Buffer.from(writer.arrayBuffer);
1275                                                                 fs.writeFileSync(writePath, taggedSongBuffer);
1276                                                                 fs.remove(tempPath);
1277                                                         }
1278
1279                                                         callback();
1280                                                 });
1281                                         }
1282                                 });
1283                         });
1284                 });
1285         }
1286
1287         function checkIfAlreadyInQueue(id) {
1288                 let exists = false;
1289                 for (let i = 0; i < socket.downloadQueue.length; i++) {
1290                         if (socket.downloadQueue[i].id == id) {
1291                                 exists = socket.downloadQueue[i].queueId;
1292                         }
1293                 }
1294                 if (socket.currentItem && (socket.currentItem.id == id)) {
1295                         exists = socket.currentItem.queueId;
1296                 }
1297                 return exists;
1298         }
1299 });
1300
1301 // Helper functions
1302
1303 /**
1304  * Updates individual parameters in the settings file
1305  * @param config
1306  * @param value
1307  */
1308 function updateSettingsFile(config, value) {
1309         configFile.userDefined[config] = value;
1310
1311         fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
1312                 if (err) return;
1313                 logger.logs('Info',"Settings updated");
1314
1315                 // FIXME: Endless Loop, due to call from initFolders()...crashes soon after startup
1316                 // initFolders();
1317         });
1318 }
1319
1320 function fixName (txt) {
1321   const regEx = /[\0\/\\:*?"<>|]/g;
1322   return txt.replace(regEx, '_');
1323 }
1324
1325 function antiDot(str){
1326         while(str[str.length-1] == "." || str[str.length-1] == " " || str[str.length-1] == "\n"){
1327                 str = str.substring(0,str.length-1);
1328         }
1329         if(str.length < 1){
1330                 str = "dot";
1331         }
1332         return fixName(str);
1333 }
1334
1335 /**
1336  * Initialize the temp folder for covers and main folder for downloads
1337  */
1338 function initFolders() {
1339         // Check if main folder exists
1340         if (!fs.existsSync(mainFolder)) {
1341                 mainFolder = defaultDownloadDir;
1342                 updateSettingsFile('downloadLocation', defaultDownloadDir);
1343         }
1344
1345         fs.removeSync(coverArtFolder);
1346         fs.ensureDirSync(coverArtFolder);
1347
1348 }
1349
1350 /**
1351  * Creates the name of the tracks replacing wildcards to correct metadata
1352  * @param metadata
1353  * @param filename
1354  * @param playlist
1355  * @returns {XML|string|*}
1356  */
1357 function settingsRegex(metadata, filename, playlist) {
1358         filename = filename.replace(/%title%/g, metadata.title);
1359         filename = filename.replace(/%album%/g, metadata.album);
1360         filename = filename.replace(/%artist%/g, metadata.artist);
1361         filename = filename.replace(/%year%/g, metadata.year);
1362         if(typeof metadata.trackNumber != 'undefined'){
1363                 if(configFile.userDefined.padtrck){
1364                          filename = filename.replace(/%number%/g, pad(splitNumber(metadata.trackNumber, false), splitNumber(metadata.trackNumber, true)));
1365                 }else{
1366                         filename = filename.replace(/%number%/g, splitNumber(metadata.trackNumber, false));
1367                 }
1368         } else {
1369                 filename = filename.replace(/%number%/g, '');
1370         }
1371         return filename;
1372 }
1373
1374 /**
1375  * Creates the name of the albums folder replacing wildcards to correct metadata
1376  * @param metadata
1377  * @param foldername
1378  * @returns {XML|string|*}
1379  */
1380 function settingsRegexAlbum(metadata, foldername, artist, album) {
1381         foldername = foldername.replace(/%album%/g, album);
1382         foldername = foldername.replace(/%artist%/g, artist);
1383         foldername = foldername.replace(/%year%/g, metadata.year);
1384         foldername = foldername.replace(/%type%/g, metadata.rtype);
1385         return foldername;
1386 }
1387
1388 /**
1389  * I really don't understand what this does ... but it does something
1390  * @param str
1391  * @param max
1392  * @returns {String|string|*}
1393  */
1394 function pad(str, max) {
1395         str = str.toString();
1396         max = max.toString();
1397         return str.length < max.length || str.length == 1 ? pad("0" + str, max) : str;
1398 }
1399
1400 /**
1401  * Splits the %number%
1402  * @param string str
1403  * @return string
1404  */
1405 function splitNumber(str,total){
1406         str = str.toString();
1407         var i = str.indexOf("/");
1408         if(total && i > 0){
1409                 return str.slice(i+1, str.length);
1410         }else if(i > 0){
1411                 return str.slice(0, i);
1412         }else{
1413                 return str;
1414         }
1415         return i > 0 ? str.slice(0, i) : str;
1416 }
1417
1418 // Show crash error in console for debugging
1419 process.on('uncaughtException', function (err) {
1420         logger.logs('Error',err.stack,function(){
1421                 socket.emit("message", "Critical Error, report to the developer", err.stack);
1422         });
1423 });
1424
1425 // Exporting vars
1426 module.exports.mainFolder = mainFolder;
1427 module.exports.defaultSettings = defaultSettings;
1428 module.exports.defaultDownloadDir = defaultDownloadDir;