5e845843665da054d1a35b268f03016d38fbe3c0
[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('./lib/flac-metadata');
18 const io = require('socket.io').listen(server, {log: false, wsEngine: 'ws'});
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 const queue = require('queue')
31
32 // Load Config File
33 var userdata = "";
34 var homedata = "";
35 if(process.env.APPDATA){
36         homedata = os.homedir();
37         userdata = process.env.APPDATA + path.sep + "Deezloader Remix" + path.sep;
38 }else if(process.platform == "darwin"){
39         homedata = os.homedir();
40         userdata = homedata + '/Library/Application Support/Deezloader Remix/';
41 }else if(process.platform == "android"){
42         homedata = os.homedir() + "/storage/shared";
43         userdata = homedata + "/Deezloader Remix/";
44 }else{
45         homedata = os.homedir();
46         userdata = homedata + '/.config/Deezloader Remix/';
47 }
48
49 if(!fs.existsSync(userdata+"config.json")){
50         fs.outputFileSync(userdata+"config.json",fs.readFileSync(__dirname+path.sep+"default.json",'utf8'));
51 }
52
53 var spotifyApi = new Spotify(authCredentials);
54
55 // Main Constants
56 const configFileLocation = userdata+"config.json";
57 const autologinLocation = userdata+"autologin";
58 const coverArtFolder = os.tmpdir() + path.sep + 'deezloader-imgs' + path.sep;
59 const defaultDownloadDir = homedata + path.sep + "Music" + path.sep + 'Deezloader' + path.sep;
60 const defaultSettings = require('./default.json').userDefined;
61
62 // Setup the folders START
63 var mainFolder = defaultDownloadDir;
64
65 // Settings update fix
66 var configFile = require(userdata+path.sep+"config.json");
67 for (let x in defaultSettings){
68         if (typeof configFile.userDefined[x] != typeof defaultSettings[x]){
69                 configFile.userDefined[x] = defaultSettings[x]
70         }
71 }
72
73 if (configFile.userDefined.downloadLocation != "") {
74         mainFolder = configFile.userDefined.downloadLocation;
75 }
76
77 initFolders();
78 // END
79
80 // Route and Create server
81 app.use('/', express.static(__dirname + '/public/'));
82 server.listen(configFile.serverPort);
83 logger.info('Server is running @ localhost:' + configFile.serverPort);
84
85 //Autologin encryption/decryption
86 var ekey = "62I9smDurjvfOdn2JhUdi99yeoAhxikw";
87
88 function alencrypt(input) {
89         let iv = crypto.randomBytes(16);
90         let data = new Buffer(input).toString('binary');
91         key = new Buffer(ekey, "utf8");
92         let cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
93         let encrypted;
94         encrypted =  cipher.update(data, 'utf8', 'binary') +  cipher.final('binary');
95         let encoded = new Buffer(iv, 'binary').toString('hex') + new Buffer(encrypted, 'binary').toString('hex');
96
97         return encoded;
98 }
99
100 function aldecrypt(encoded) {
101         let combined = new Buffer(encoded, 'hex');
102         key = new Buffer(ekey, "utf8");
103         // Create iv
104         let iv = new Buffer(16);
105         combined.copy(iv, 0, 0, 16);
106         edata = combined.slice(16).toString('binary');
107         // Decipher encrypted data
108         let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
109         let decrypted, plaintext;
110         plaintext = (decipher.update(edata, 'binary', 'utf8') + decipher.final('utf8'));
111
112         return plaintext;
113 }
114
115 // START sockets clusterfuck
116 io.sockets.on('connection', function (socket) {
117         socket.downloadQueue = {};
118         socket.currentItem = null;
119         socket.lastQueueId = null;
120         socket.trackQueue = queue({
121                 autostart: true
122         });
123         socket.trackQueue.concurrency = configFile.userDefined.queueConcurrency;
124
125         socket.on("login", function (username, password, autologin) {
126                 Deezer.init(username, password, function (err) {
127                         if(err){
128                                 socket.emit("login", {error: err.message});
129                                 logger.error("Failed to login, "+err.stack);
130                         }else{
131                                 if(autologin){
132                                         let data = username + "\n" + password;
133                                         fs.outputFile(autologinLocation, alencrypt(data) , function(){
134                                                 if(!err){
135                                                         logger.info("Added autologin successfully");
136                                                 }else{
137                                                         logger.info("Failed to add autologin file");
138                                                 }
139                                         });
140                                 }
141                                 socket.emit("login", {username: Deezer.userName, picture: Deezer.userPicture});
142                                 logger.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.info("No auto login found");
151                                 return;
152                         }
153                         try{
154                                 var fdata = aldecrypt(data.toString('utf8'));
155
156                         }catch(e){
157                                 logger.warn("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.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                 if(track.trackSocket.currentItem && track.trackSocket.currentItem.type == "track"){
179                         let complete;
180                         if (!track.trackSocket.currentItem.percentage) {
181                                 track.trackSocket.currentItem.percentage = 0;
182                         }
183                         if(track.format == 9){
184                                 complete = track.FILESIZE_FLAC;
185                         }else{
186                                 if (track.FILESIZE_MP3_320) {
187                                         complete = track.FILESIZE_MP3_320;
188                                 } else if (track.FILESIZE_MP3_256) {
189                                         complete = track.FILESIZE_MP3_256;
190                                 } else {
191                                         complete = track.FILESIZE_MP3_128 || 0;
192                                 }
193                         }
194                         let percentage = (progress / complete) * 100;
195                         if ((percentage - track.trackSocket.currentItem.percentage > 1) || (progress == complete)) {
196                                 track.trackSocket.currentItem.percentage = percentage;
197                                 track.trackSocket.emit("downloadProgress", {
198                                         queueId: track.trackSocket.currentItem.queueId,
199                                         percentage: track.trackSocket.currentItem.percentage
200                                 });
201                         }
202                 }
203         };
204
205         function addToQueue(object) {
206                 socket.downloadQueue[object.queueId] = object;
207                 socket.emit('addToQueue', object);
208                 queueDownload(getNextDownload());
209         }
210
211         function getNextDownload() {
212                 if (socket.currentItem != null || Object.keys(socket.downloadQueue).length == 0) {
213                         if (Object.keys(socket.downloadQueue).length == 0 && socket.currentItem == null) {
214                                 socket.emit("emptyDownloadQueue", {});
215                         }
216                         return null;
217                 }
218                 socket.currentItem = socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
219                 return socket.currentItem;
220         }
221
222         function socketDownloadTrack(data){
223                 Deezer.getTrack(data.id, data.settings.hifi, function (track, err) {
224                         if (err) {
225                                 return;
226                         }
227                         let queueId = "id" + Math.random().toString(36).substring(2);
228                         let _track = {
229                                 name: track["SNG_TITLE"],
230                                 artist: track["ART_NAME"],
231                                 size: 1,
232                                 downloaded: 0,
233                                 failed: 0,
234                                 queueId: queueId,
235                                 id: track["SNG_ID"],
236                                 type: "track"
237                         };
238                         data.settings.trackInfo= slimDownTrackInfo(track);
239                         if (track["VERSION"]) _track.name = _track.name + " " + track["VERSION"];
240                         _track.settings = data.settings || {};
241                         addToQueue(_track);
242                 });
243         }
244         socket.on("downloadtrack", data=>{socketDownloadTrack(data)});
245
246         function socketDownloadPlaylist(data){
247                 Deezer.getPlaylist(data.id, function (playlist, err) {
248                         if (err) {
249                                 return;
250                         }
251                         let queueId = "id" + Math.random().toString(36).substring(2);
252                         let _playlist = {
253                                 name: playlist["title"],
254                                 size: playlist.nb_tracks,
255                                 downloaded: 0,
256                                 artist: playlist.creator.name,
257                                 failed: 0,
258                                 queueId: queueId,
259                                 id: playlist["id"],
260                                 type: "playlist",
261                                 cover: playlist["picture_small"],
262                                 tracks: playlist.tracks.data
263                         };
264                         _playlist.settings = data.settings || {};
265                         if (_playlist.size>400){
266                                 Deezer.getPlaylistTracks(data.id, function (playlist, err) {
267                                         _playlist.size = playlist.data.length
268                                         _playlist.tracks = playlist.data
269                                         addToQueue(_playlist);
270                                 })
271                         }else{
272                                 addToQueue(_playlist);
273                         }
274                 });
275         }
276         socket.on("downloadplaylist", data=>{socketDownloadPlaylist(data)});
277
278         function socketDownloadAlbum(data){
279                 Deezer.getAlbum(data.id, function (album, err) {
280                         if (err) {
281                                 return;
282                         }
283                         let queueId = "id" + Math.random().toString(36).substring(2);
284                         let _album = {
285                                 name: album["title"],
286                                 label: album["label"],
287                                 artist: album["artist"].name,
288                                 size: album.tracks.data.length,
289                                 downloaded: 0,
290                                 failed: 0,
291                                 queueId: queueId,
292                                 id: album["id"],
293                                 type: "album",
294                                 tracks: album.tracks.data
295                         };
296                         data.settings.albumInfo = slimDownAlbumInfo(album)
297                         _album.settings = data.settings || {};
298                         addToQueue(_album);
299                 });
300         }
301         socket.on("downloadalbum", data=>{socketDownloadAlbum(data)});
302
303         function socketDownloadArtist(data){
304                 Deezer.getArtistAlbums(data.id, function (albums, err) {
305                         if (err) {
306                                 return;
307                         }
308                         (function sendAllAlbums(i) {
309                                 setTimeout(function () {
310                       data.id = albums.data[albums.data.length-1-i].id;
311                                         socketDownloadAlbum(data);
312                       if (--i+1) sendAllAlbums(i);
313                         }, 100)
314                         })(albums.data.length-1);
315                 });
316         }
317         socket.on("downloadartist", data=>{socketDownloadArtist(data)});
318
319
320         socket.on("downloadspotifyplaylist", function (data) {
321                 spotifyApi.clientCredentialsGrant().then(function(creds) {
322                         spotifyApi.setAccessToken(creds.body['access_token']);
323                         return spotifyApi.getPlaylist(data.settings.currentSpotifyUser, data.id, {fields: "id,name,owner,images,tracks(total,items(track.artists,track.name))"})
324                 }).then(function(resp) {
325                         let queueId = "id" + Math.random().toString(36).substring(2);
326                         let _playlist = {
327                                 name: resp.body["name"],
328                                 artist: (resp.body["owner"]["display_name"] ? resp.body["owner"]["display_name"] : resp.body["owner"]["id"]),
329                                 size: resp.body["tracks"]["total"],
330                                 downloaded: 0,
331                                 failed: 0,
332                                 queueId: queueId,
333                                 id: resp.body["id"],
334                                 type: "spotifyplaylist",
335                                 cover: (resp.body["images"] ? resp.body["images"][0]["url"] : null),
336                                 tracks: resp.body["tracks"]["items"]
337                         };
338                         _playlist.settings = data.settings || {};
339                         addToQueue(_playlist);
340                 })
341         });
342
343         //currentItem: the current item being downloaded at that moment such as a track or an album
344         //downloadQueue: the tracks in the queue to be downloaded
345         //lastQueueId: the most recent queueId
346         //queueId: random number generated when user clicks download on something
347         function queueDownload(downloading) {
348                 if (!downloading) return;
349
350                 // New batch emits new message
351                 if (socket.lastQueueId != downloading.queueId) {
352                         if (downloading.type != "spotifyplaylist"){
353                                 socket.emit("downloadStarted", {queueId: downloading.queueId});
354                         }
355                         socket.lastQueueId = downloading.queueId;
356                 }
357
358                 logger.info(`Registered ${downloading.type}: ${downloading.id} | ${downloading.artist} - ${downloading.name}`);
359                 switch(downloading.type){
360                         case "track":
361                                 let alternativeID = 0;
362                                 if (downloading.settings.trackInfo.FALLBACK)
363                                         if (downloading.settings.trackInfo.FALLBACK.SNG_ID)
364                                                 alternativeID = downloading.settings.trackInfo.FALLBACK.SNG_ID;
365                                 downloadTrack({id: downloading.id, fallback: (alternativeID == 0 ? null : alternativeID), name: downloading.name, artist: downloading.artist, queueId: downloading.queueId}, downloading.settings, null, function (err, track) {
366                                         if (err) {
367                                                 downloading.failed++;
368                                         } else {
369                                                 downloading.downloaded++;
370                                         }
371                                         downloading.settings = null;
372                                         socket.emit("updateQueue", downloading);
373                                         socket.emit("downloadProgress", {
374                                                 queueId: downloading.queueId,
375                                                 percentage: 100
376                                         });
377                                         if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
378                                         socket.currentItem = null;
379                                         queueDownload(getNextDownload());
380                                 });
381                                 break;
382                         case "album":
383                                 downloading.playlistContent = downloading.tracks.map((t) => {
384                                         if (t.FALLBACK){
385                                                 if (t.FALLBACK.SNG_ID)
386                                                         return {id: t.id, fallback: t.FALLBACK.SNG_ID, name: t.title, artist: t.artist.name, queueId: downloading.queueId}
387                                         }else{
388                                                 return {id: t.id, name: t.title, artist: t.artist.name, queueId: downloading.queueId}
389                                         }
390                                 })
391                                 downloading.settings.albName = downloading.name;
392                                 downloading.settings.artName = downloading.artist;
393                                 downloading.errorLog = "";
394                                 downloading.settings.playlistArr = Array(downloading.size);
395                                 downloading.finished = new Promise((resolve,reject)=>{
396                                         downloading.playlistContent.every(function (t) {
397                                                 socket.trackQueue.push(cb=>{
398                                                         if (!socket.downloadQueue[downloading.queueId]) {
399                                                                 reject();
400                                                                 return false;
401                                                         }
402                                                         logger.info(`Now downloading: ${t.artist} - ${t.name}`)
403                                                         downloadTrack(t, downloading.settings, null, function (err, track) {
404                                                                 if (!err) {
405                                                                         downloading.downloaded++;
406                                                                         downloading.settings.playlistArr[track[0]] = track[1];
407                                                                 } else {
408                                                                         downloading.failed++;
409                                                                         downloading.errorLog += track+"\r\n";
410                                                                 }
411                                                                 socket.emit("downloadProgress", {
412                                                                         queueId: downloading.queueId,
413                                                                         percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
414                                                                 });
415                                                                 socket.emit("updateQueue", downloading);
416                                                                 if (downloading.downloaded + downloading.failed == downloading.size)
417                                                                         resolve();
418                                                                 cb();
419                                                         });
420                                                 });
421                                                 return true;
422                                         });
423                                 })
424                                 downloading.finished.then(()=>{
425                                         if (downloading.countPerAlbum) {
426                                                 if (Object.keys(socket.downloadQueue).length > 1 && Object.keys(socket.downloadQueue)[1] == downloading.queueId) {
427                                                         socket.downloadQueue[downloading.queueId].download = downloading.downloaded;
428                                                 }
429                                                 socket.emit("updateQueue", downloading);
430                                         }
431                                         logger.info("Album finished "+downloading.name);
432                                         socket.emit("downloadProgress", {
433                                                 queueId: downloading.queueId,
434                                                 percentage: 100
435                                         });
436                                         let filePath = mainFolder;
437                                         if (downloading.settings.createArtistFolder || downloading.settings.createAlbumFolder) {
438                                                 if (downloading.settings.createArtistFolder) {
439                                                         filePath += antiDot(fixName(downloading.settings.artName)) + path.sep;
440                                                 }
441                                                 if (downloading.settings.createAlbumFolder) {
442                                                         filePath += antiDot(fixName(settingsRegexAlbum(downloading.settings.foldername,downloading.settings.artName,downloading.settings.albName,downloading.settings.albumInfo.release_date.slice(0, 4),downloading.settings.albumInfo.record_type))) + path.sep;
443                                                 }
444                                         } else if (downloading.settings.artName) {
445                                                 filePath += antiDot(fixName(settingsRegexAlbum(downloading.settings.foldername,downloading.settings.artName,downloading.settings.albName,downloading.settings.albumInfo.release_date.slice(0, 4),downloading.settings.albumInfo.record_type))) + path.sep;
446                                         }
447                                         if (downloading.settings.logErrors){
448                                                 if (downloading.errorLog != ""){
449                                                         if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
450                                                         fs.writeFileSync(filePath+"notFound.txt",downloading.errorLog)
451                                                 }else{
452                                                         if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
453                                                 }
454                                         }
455                                         if (downloading.settings.createM3UFile){
456                                                 fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
457                                         }
458                                         if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
459                                         socket.currentItem = null;
460                                         queueDownload(getNextDownload());
461                                 }).catch((err)=>{
462                                         if (err) return logger.error(err.stack);
463                                         logger.info("Stopping the album queue");
464                                         if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
465                                         socket.currentItem = null;
466                                         queueDownload(getNextDownload());
467                                 });
468                                 break;
469                         case "playlist":
470                                 downloading.playlistContent = downloading.tracks.map((t,i) => {
471                                         if (t.FALLBACK){
472                                                 if (t.FALLBACK.SNG_ID)
473                                                         return {id: t.id, fallback: t.FALLBACK.SNG_ID, name: t.title, artist: t.artist.name, index: i, queueId: downloading.queueId}
474                                         }else{
475                                                 return {id: t.id, name: t.title, artist: t.artist.name, index: i, queueId: downloading.queueId}
476                                         }
477                                 })
478                                 downloading.settings.plName = downloading.name;
479                                 downloading.errorLog = ""
480                                 downloading.settings.playlistArr = Array(downloading.size);
481                                 downloading.settings.playlist = {
482                                         fullSize: downloading.playlistContent.length
483                                 };
484                                 downloading.finished = new Promise((resolve,reject)=>{
485                                         downloading.playlistContent.every(function (t) {
486                                                 socket.trackQueue.push(cb=>{
487                                                         if (!socket.downloadQueue[downloading.queueId]) {
488                                                                 reject();
489                                                                 return false;
490                                                         }
491                                                         logger.info(`Now downloading: ${t.artist} - ${t.name}`)
492                                                         downloadTrack(t, downloading.settings, null, function (err, track) {
493                                                                 if (!err) {
494                                                                         downloading.downloaded++;
495                                                                         downloading.settings.playlistArr[track[0]] = track[1];
496                                                                 } else {
497                                                                         downloading.failed++;
498                                                                         downloading.errorLog += track+"\r\n"
499                                                                 }
500                                                                 socket.emit("downloadProgress", {
501                                                                         queueId: downloading.queueId,
502                                                                         percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
503                                                                 });
504                                                                 socket.emit("updateQueue", downloading);
505                                                                 if (downloading.downloaded + downloading.failed == downloading.size)
506                                                                         resolve();
507                                                                 cb();
508                                                         });
509                                                 });
510                                                 return true;
511                                         })
512                                 });
513                                 downloading.finished.then(()=>{
514                                         logger.info("Playlist finished "+downloading.name);
515                                         socket.emit("downloadProgress", {
516                                                 queueId: downloading.queueId,
517                                                 percentage: 100
518                                         });
519                                         let filePath = mainFolder+antiDot(fixName(downloading.settings.plName)) + path.sep
520                                         if (downloading.settings.logErrors){
521                                                 if (downloading.errorLog != ""){
522                                                         if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
523                                                         fs.writeFileSync(filePath+"notFound.txt",downloading.errorLog)
524                                                 }else{
525                                                         if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
526                                                 }
527                                         }
528                                         if (downloading.settings.createM3UFile){
529                                                 fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
530                                         }
531                                         if (downloading.settings.saveArtwork){
532                                                 if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
533                                                 let imgPath = filePath + "folder.jpg";
534                                                 if (downloading.cover){
535                                                         downloading.cover = downloading.cover.replace("56x56",downloading.settings.artworkSize.split(".")[0].substr(1))
536                                                         request.get(downloading.cover, {encoding: 'binary'}, function(error,response,body){
537                                                                 if(error){
538                                                                         logger.error(error.stack);
539                                                                         return;
540                                                                 }
541                                                                 fs.outputFile(imgPath,body,'binary',function(err){
542                                                                         if(err){
543                                                                                 logger.error(err.stack);
544                                                                                 return;
545                                                                         }
546                                                                         logger.info(`Cover downloaded for: ${downloading.settings.plName}`)
547                                                                 })
548                                                         });
549                                                 }
550                                         }
551                                         if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
552                                         socket.currentItem = null;
553                                         queueDownload(getNextDownload());
554                                 }).catch((err)=>{
555                                         if (err) return logger.error(err.stack);
556                                         logger.info("Stopping the playlist queue");
557                                         if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
558                                         socket.currentItem = null;
559                                         queueDownload(getNextDownload());
560                                 });
561                                 break;
562                         case "spotifyplaylist":
563                         spotifyApi.clientCredentialsGrant().then(function(creds) {
564                                 downloading.settings.plName = downloading.name;
565                                 downloading.settings.playlistArr = Array(downloading.size);
566                                 spotifyApi.setAccessToken(creds.body['access_token']);
567                                 numPages=Math.floor((downloading.size-1)/100);
568                                 let pages = []
569                                 downloading.playlistContent = new Array(downloading.size);
570                                 downloading.tracks.map((t,i)=>{
571                                         downloading.playlistContent[i]=new Promise(function(resolve, reject) {
572                                                 Deezer.track2ID(t.track.artists[0].name, t.track.name, function (response,err){
573                                                         resolve(response);
574                                                 });
575                                         });
576                                 })
577                                 if (downloading.size>100){
578                                         for (let offset = 1; offset<=numPages; offset++){
579                                                 pages.push(new Promise(function(resolvePage) {
580                                                         spotifyApi.getPlaylistTracks(downloading.settings.currentSpotifyUser, downloading.id, {fields: "items(track.artists,track.name)", offset: offset*100}).then(function(resp) {
581                                                                 resp.body['items'].forEach((t, index) => {
582                                                                         downloading.playlistContent[(offset*100)+index] = new Promise(function(resolve, reject) {
583                                                                                 Deezer.track2ID(t.track.artists[0].name, t.track.name, function (response,err){
584                                                                                         resolve(response);
585                                                                                 });
586                                                                         });
587                                                                 });
588                                                                 resolvePage();
589                                                         });
590                                                 }));
591                                         }
592                                 }
593                                 logger.info("Waiting for all pages");
594                                 Promise.all(pages).then((val)=>{
595                                         logger.info("Waiting for all tracks to be converted");
596                                         return Promise.all(downloading.playlistContent)
597                                 }).then((values)=>{
598                                         if (!socket.downloadQueue[downloading.queueId]) {
599                                                 logger.info("Stopping the playlist queue");
600                                                 if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
601                                                 socket.currentItem = null;
602                                                 queueDownload(getNextDownload());
603                                                 return;
604                                         }
605                                         logger.info("All tracks converted, starting download");
606                                         socket.emit("downloadStarted", {queueId: downloading.queueId});
607                                         downloading.errorLog = "";
608                                         downloading.settings.playlist = {
609                                                 fullSize: values.length
610                                         };
611                                         downloading.finished = new Promise((resolve,reject)=>{
612                                                 values.every(function (t) {
613                                                         t.index = values.indexOf(t)
614                                                         t.queueId = downloading.queueId
615                                                         socket.trackQueue.push(cb=>{
616                                                                 if (!socket.downloadQueue[downloading.queueId]) {
617                                                                         reject();
618                                                                         return false;
619                                                                 }
620                                                                 logger.info(`Now downloading: ${t.artist} - ${t.name}`)
621                                                                 downloadTrack(t, downloading.settings, null, function (err, track) {
622                                                                         if (!err) {
623                                                                                 downloading.downloaded++;
624                                                                                 downloading.settings.playlistArr[track[0]] = track[1];
625                                                                         } else {
626                                                                                 downloading.failed++;
627                                                                                 downloading.errorLog += track+"\r\n"
628                                                                         }
629                                                                         socket.emit("downloadProgress", {
630                                                                                 queueId: downloading.queueId,
631                                                                                 percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
632                                                                         });
633                                                                         if (downloading.downloaded + downloading.failed == downloading.size)
634                                                                                 resolve();
635                                                                         socket.emit("updateQueue", downloading);
636                                                                         cb();
637                                                                 });
638                                                         });
639                                                         return true;
640                                                 });
641                                         });
642                                         downloading.finished.then(()=>{
643                                                 logger.info("Playlist finished "+downloading.name);
644                                                 socket.emit("downloadProgress", {
645                                                         queueId: downloading.queueId,
646                                                         percentage: 100
647                                                 });
648                                                 let filePath = mainFolder+antiDot(fixName(downloading.settings.plName)) + path.sep
649                                                 if (downloading.settings.logErrors){
650                                                         if (downloading.errorLog != ""){
651                                                                 if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
652                                                                 fs.writeFileSync(filePath+"notFound.txt",downloading.errorLog)
653                                                         }else{
654                                                                 if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
655                                                         }
656                                                 }
657                                                 if (downloading.settings.createM3UFile){
658                                                         fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
659                                                 }
660                                                 if (downloading.settings.saveArtwork){
661                                                         if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
662                                                         let imgPath = filePath + "folder.jpg";
663                                                         if (downloading.cover){
664                                                                 request.get(downloading.cover, {encoding: 'binary'}, function(error,response,body){
665                                                                         if(error){
666                                                                                 logger.error(error.stack);
667                                                                                 return;
668                                                                         }
669                                                                         fs.outputFile(imgPath,body,'binary',function(err){
670                                                                                 if(err){
671                                                                                         logger.error(err.stack);
672                                                                                         return;
673                                                                                 }
674                                                                                 logger.info(`Cover downloaded for: ${downloading.settings.plName}`)
675                                                                         })
676                                                                 });
677                                                         }
678                                                 }
679                                                 if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
680                                                 socket.currentItem = null;
681                                                 queueDownload(getNextDownload());
682                                         }).catch((err)=>{
683                                                 if (err) return logger.error(err.stack);
684                                                 logger.info("Stopping the playlist queue");
685                                                 if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
686                                                 socket.currentItem = null;
687                                                 queueDownload(getNextDownload());
688                                         });
689                                 }).catch((err)=>{
690                                         logger.error('Something went wrong!'+err.stack);
691                                 });
692                         }).catch((err)=>{
693                                 logger.error('Something went wrong!'+err.stack);
694                         });
695                         break;
696                 }
697         }
698
699         socket.on("getChartsCountryList", function (data) {
700                 Deezer.getChartsTopCountry(function (charts, err) {
701                         if(err){
702                                 return;
703                         }
704                         if(charts){
705                                 charts = charts.data || [];
706                         }else{
707                                 charts = [];
708                         }
709                         let countries = [];
710                         for (let i = 0; i < charts.length; i++) {
711                                 let obj = {
712                                         country: charts[i].title.replace("Top ", ""),
713                                         picture_small: charts[i].picture_small,
714                                         picture_medium: charts[i].picture_medium,
715                                         picture_big: charts[i].picture_big
716                                 };
717                                 countries.push(obj);
718                         }
719                         socket.emit("getChartsCountryList", {countries: countries, selected: data.selected});
720                 });
721         });
722
723         socket.on("getChartsTrackListByCountry", function (data) {
724                 if (!data.country) {
725                         socket.emit("getChartsTrackListByCountry", {err: "No country passed"});
726                         return;
727                 }
728                 Deezer.getChartsTopCountry(function (charts, err) {
729                         if(err) return;
730                         if(charts){
731                                 charts = charts.data || [];
732                         }else{
733                                 charts = [];
734                         }
735                         let countries = [];
736                         for (let i = 0; i < charts.length; i++) {
737                                 countries.push(charts[i].title.replace("Top ", ""));
738                         }
739
740                         if (countries.indexOf(data.country) == -1) {
741                                 socket.emit("getChartsTrackListByCountry", {err: "Country not found"});
742                                 return;
743                         }
744                         let playlistId = charts[countries.indexOf(data.country)].id;
745                         Deezer.getPlaylistTracks(playlistId, function (tracks, err) {
746                                 if (err) {
747                                         socket.emit("getChartsTrackListByCountry", {err: err});
748                                         return;
749                                 }
750                                 socket.emit("getChartsTrackListByCountry", {
751                                         playlist: charts[countries.indexOf(data.country)],
752                                         tracks: tracks.data
753                                 });
754                         });
755                 });
756         });
757
758         socket.on("getMePlaylistList", function (d) {
759                 logger.info("Loading Personal Playlists")
760                 Deezer.getMePlaylists(function (data, err) {
761                         if(err){
762                                 return;
763                         }
764                         if(data){
765                                 data = data.data || [];
766                         }else{
767                                 data = [];
768                         }
769                         let playlists = [];
770                         for (let i = 0; i < data.length; i++) {
771                                 let obj = {
772                                         title: data[i].title,
773                                         image: data[i].picture_small,
774                                         songs: data[i].nb_tracks,
775                                         link: data[i].link
776                                 };
777                                 playlists.push(obj);
778                         }
779                         if (configFile.userDefined.spotifyUser){
780                                 spotifyApi.clientCredentialsGrant().then(function(creds) {
781                                         spotifyApi.setAccessToken(creds.body['access_token']);
782                                         spotifyApi.getUserPlaylists(configFile.userDefined.spotifyUser, {fields: "total"}).then(data=>{
783                                                 let total = data.body.total
784                                                 let numPages=Math.floor((total-1)/20);
785                                                 let pages = [];
786                                                 let playlistList = new Array(total);
787                                                 for (let offset = 0; offset<=numPages; offset++){
788                                                         pages.push(new Promise(function(resolvePage) {
789                                                                 spotifyApi.getUserPlaylists(configFile.userDefined.spotifyUser, {fields: "items(images,name,owner.id,tracks.total,uri)", offset: offset*20}).then(data=>{
790                                                                         data.body.items.forEach((playlist, i)=>{
791                                                                                 playlistList[(offset*20)+i] = {
792                                                                                         title: playlist.name,
793                                                                                         image: (playlist.images[0] ? playlist.images[0].url : ""),
794                                                                                         songs: playlist.tracks.total,
795                                                                                         link: playlist.uri
796                                                                                 };
797                                                                         });
798                                                                         resolvePage();
799                                                                 });
800                                                         }));
801                                                 }
802                                                 Promise.all(pages).then(()=>{
803                                                         playlists = playlists.concat(playlistList);
804                                                         logger.info(`Loaded ${playlists.length} Playlist${playlists.length>1 ? "s" : ""}`);
805                                                         socket.emit("getMePlaylistList", {playlists: playlists});
806                                                 });
807                                         }).catch(err=>{
808                                                 logger.error(err.stack);
809                                         });
810                                 }).catch(err=>{
811                                         logger.error(err.stack);
812                                 });
813                         }else{
814                                 logger.info(`Loaded ${playlists.length} Playlist${playlists.length>1 ? "s" : ""}`);
815                                 socket.emit("getMePlaylistList", {playlists: playlists});
816                         }
817                 });
818         });
819
820         socket.on("search", function (data) {
821                 data.type = data.type || "track";
822                 if (["track", "playlist", "album", "artist"].indexOf(data.type) == -1) data.type = "track";
823
824                 // Remove "feat."  "ft." and "&" (causes only problems)
825                 data.text = data.text.replace(/ feat[\.]? /g, " ").replace(/ ft[\.]? /g, " ").replace(/\(feat[\.]? /g, " ").replace(/\(ft[\.]? /g, " ").replace(/\&/g, "");
826
827                 Deezer.search(encodeURIComponent(data.text), data.type, function (searchObject, err) {
828                         try {
829                                 socket.emit("search", {type: data.type, items: searchObject.data});
830                         } catch (e) {
831                                 socket.emit("search", {type: data.type, items: []});
832                         }
833                 });
834         });
835
836         socket.on("getTrackList", function (data) {
837                 if (!data.type || (["playlist", "album", "artist"].indexOf(data.type) == -1) || !data.id) {
838                         socket.emit("getTrackList", {err: -1, response: {}, id: data.id, reqType: data.type});
839                         return;
840                 }
841                 if (data.type == 'artist') {
842                         Deezer.getArtistAlbums(data.id, function (response, err) {
843                                 if (err) {
844                                         socket.emit("getTrackList", {err: "wrong id artist", response: {}, id: data.id, reqType: data.type});
845                                         return;
846                                 }
847                                 socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
848                         });
849                 } else {
850                         let reqType = data.type.charAt(0).toUpperCase() + data.type.slice(1);
851                         Deezer["get" + reqType + "Tracks"](data.id, function (response, err) {
852                                 if (err) {
853                                         socket.emit("getTrackList", {err: "wrong id "+reqType, response: {}, id: data.id, reqType: data.type});
854                                         return;
855                                 }
856                                 socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
857                         });
858                 }
859         });
860
861         socket.on("cancelDownload", function (data) {
862                 if (!data.queueId) {
863                         return;
864                 }
865                 let cancel = false;
866                 let cancelSuccess;
867                 if (socket.downloadQueue[data.queueId]){
868                         cancel = true;
869                         delete socket.downloadQueue[data.queueId];
870                 }
871                 if (socket.currentItem && socket.currentItem.queueId == data.queueId) {
872                         cancelSuccess = Deezer.cancelDecryptTrack(data.queueId);
873                         socket.trackQueue = queue({
874                                 autostart: true,
875                                 concurrency: socket.trackQueue.concurrency
876                         })
877                         cancel = cancel || cancelSuccess;
878                 }
879                 if (cancel) {
880                         socket.emit("cancelDownload", {queueId: data.queueId});
881                 }
882         });
883
884         socket.on("downloadAlreadyInQueue", function (data) {
885                 if (data.id) {
886                         return;
887                 }
888                 let isInQueue = checkIfAlreadyInQueue(data.id);
889                 if (isInQueue) {
890                         socket.emit("downloadAlreadyInQueue", {alreadyInQueue: true, id: data.id, queueId: isInQueue});
891                 } else {
892                         socket.emit("downloadAlreadyInQueue", {alreadyInQueue: false, id: data.id});
893                 }
894         });
895
896         socket.on("getUserSettings", function () {
897                 let settings = configFile.userDefined;
898                 if (!settings.downloadLocation) {
899                         settings.downloadLocation = mainFolder;
900                 }
901                 socket.emit('getUserSettings', {settings: settings});
902         });
903
904         socket.on("saveSettings", function (settings) {
905                 if (settings.userDefined.downloadLocation == defaultDownloadDir) {
906                         settings.userDefined.downloadLocation = "";
907                 } else {
908                         settings.userDefined.downloadLocation = path.resolve(settings.userDefined.downloadLocation + path.sep) + path.sep;
909                         mainFolder = settings.userDefined.downloadLocation;
910                 }
911
912                 if (settings.userDefined.queueConcurrency < 1) settings.userDefined.queueConcurrency = 1;
913
914                 if (settings.userDefined.queueConcurrency != socket.trackQueue.concurrency){
915                         socket.trackQueue.concurrency = settings.userDefined.queueConcurrency;
916                 }
917
918                 if (settings.userDefined.chartsCountry != configFile.userDefined.chartsCountry){
919                         socket.emit("setChartsCountry", {selected: settings.userDefined.chartsCountry});
920                         Deezer.getChartsTopCountry(function (charts, err) {
921                                 if(err){
922                                         return;
923                                 }
924                                 if(charts){
925                                         charts = charts.data || [];
926                                 }else{
927                                         charts = [];
928                                 }
929                                 let countries = [];
930                                 for (let i = 0; i < charts.length; i++) {
931                                         countries.push(charts[i].title.replace("Top ", ""));
932                                 }
933
934                                 if (countries.indexOf(settings.userDefined.chartsCountry) == -1) {
935                                         socket.emit("getChartsTrackListByCountry", {err: "Country not found"});
936                                         return;
937                                 }
938
939                                 let playlistId = charts[countries.indexOf(settings.userDefined.chartsCountry)].id;
940
941                                 Deezer.getPlaylistTracks(playlistId, function (tracks, err) {
942                                         if (err) {
943                                                 socket.emit("getChartsTrackListByCountry", {err: err});
944                                                 return;
945                                         }
946                                         socket.emit("getChartsTrackListByCountry", {
947                                                 playlist: charts[countries.indexOf(settings.userDefined.chartsCountry)],
948                                                 tracks: tracks.data
949                                         });
950                                 });
951                         });
952                 }
953
954                 configFile.userDefined = settings.userDefined;
955                 fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
956                         if (err) return;
957                         logger.info("Settings updated");
958                         initFolders();
959                 });
960         });
961
962         function downloadTrack(t, settings, altmetadata, callback) {
963                 if (!socket.downloadQueue[t.queueId]) {
964                         logger.error("Not in queue");
965                         callback(new Error("Not in queue"), `${t.id} | ${t.artist} - ${t.name}`);
966                         return;
967                 }
968                 if (t.id == 0){
969                         logger.error("Failed to download track: Wrong ID");
970                         callback(new Error("Failed to download track: Wrong ID"), `${t.id} | ${t.artist} - ${t.name}`);
971                         return;
972                 }
973                 let temp1 = new Promise((resolve, reject)=>{
974                         if (!settings.trackInfo){
975                                 logger.info("Getting track data");
976                                 Deezer.getTrack(t.id, settings.hifi, function (trackInfo, err) {
977                                         if (err) {
978                                                 if(t.fallback){
979                                                         logger.warn("Failed to download track, falling on alternative");
980                                                         t.id = t.fallback
981                                                         t.fallback = 0
982                                                         downloadTrack(t, settings, null, function(err){
983                                                                 callback(err, `${t.id} | ${t.artist} - ${t.name}`);
984                                                         });
985                                                 }else if(!t.searched){
986                                                         logger.warn("Failed to download track, searching for alternative");
987                                                         Deezer.track2ID(t.artist, t.name, data=>{
988                                                                 t.searched = true;
989                                                                 t.id = data.id;
990                                                                 t.artist = data.artist;
991                                                                 t.name = data.name;
992                                                                 downloadTrack(t, settings, null, function(err){
993                                                                         callback(err, `${t.id} | ${t.artist} - ${t.name}`);
994                                                                 });
995                                                         });
996                                                 }else{
997                                                         logger.error("Failed to download track: "+ err);
998                                                         callback(err, `${t.id} | ${t.artist} - ${t.name}`);
999                                                 }
1000                                                 return;
1001                                         }
1002                                         resolve(trackInfo);
1003                                 });
1004                         }else{
1005                                 resolve(settings.trackInfo);
1006                         }
1007                 })
1008                 temp1.then(data=>{
1009                         let track = data;
1010                         track.trackSocket = socket;
1011                         logger.info("Getting album data");
1012                         let temp2 = new Promise((resolve, reject)=>{
1013                                 if (!settings.albumInfo){
1014                                         Deezer.getAlbum(track["ALB_ID"], function(res, err){
1015                                                 if(err){
1016                                                         if(t.fallback){
1017                                                                 logger.warn("Failed to download track, falling on alternative");
1018                                                                 t.id = t.fallback
1019                                                                 t.fallback = 0
1020                                                                 downloadTrack(t, settings, null, function(err){
1021                                                                         callback(err, `${t.id} | ${t.artist} - ${t.name}`);
1022                                                                 });
1023                                                         }else if(!t.searched){
1024                                                                 logger.warn("Failed to download track, searching for alternative");
1025                                                                 Deezer.track2ID(t.artist, t.name, data=>{
1026                                                                         t.searched = true;
1027                                                                         t.id = data.id;
1028                                                                         t.artist = data.artist;
1029                                                                         t.name = data.name;
1030                                                                         downloadTrack(t, settings, null, function(err){
1031                                                                                 callback(err, `${t.id} | ${t.artist} - ${t.name}`);
1032                                                                         });
1033                                                                 });
1034                                                         }else{
1035                                                                 logger.error("Failed to download track: "+ err);
1036                                                                 callback(new Error("Album does not exists."), `${t.id} | ${t.artist} - ${t.name}`);
1037                                                         }
1038                                                         return;
1039                                                 }
1040                                                 resolve(res);
1041                                         })
1042                                 }else{
1043                                         resolve(settings.albumInfo)
1044                                 }
1045                         });
1046                         temp2.then(res=>{
1047                                 settings = settings || {};
1048                                 let ajson = res;
1049                                 let totalDiskNumber;
1050                                 let temp3;
1051                                 if (settings.partOfSet){
1052                                         logger.info("Getting total disk number data");
1053                                         temp3 = new Promise((resolve, reject) =>{
1054                                                 Deezer.getATrack(ajson.tracks.data[ajson.tracks.data.length-1].id, function(tres){
1055                                                         totalDiskNumber = tres.disk_number;
1056                                                         resolve();
1057                                                 });
1058                                         })
1059                                 }else{
1060                                         temp3 = new Promise((resolve, reject) =>{
1061                                                 resolve()
1062                                         })
1063                                 }
1064                                 temp3.then(()=>{
1065                                         let metadata = parseMetadata(track, ajson, totalDiskNumber, settings, t.index, altmetadata);
1066                                         let filename = fixName(`${metadata.artist} - ${metadata.title}`);
1067                                         if (settings.filename) {
1068                                                 filename = fixName(settingsRegex(metadata, settings.filename, settings.playlist));
1069                                         }
1070                                         let filepath = mainFolder;
1071                                         if (settings.createArtistFolder || settings.createAlbumFolder) {
1072                                                 if(settings.plName){
1073                                                         filepath += antiDot(fixName(settings.plName)) + path.sep;
1074                                                 }
1075                                                 if (settings.createArtistFolder) {
1076                                                         if(settings.artName){
1077                                                                 filepath += antiDot(fixName(settings.artName)) + path.sep;
1078                                                         }else{
1079                                                                 filepath += antiDot(fixName(metadata.artist)) + path.sep;
1080                                                         }
1081                                                 }
1082
1083                                                 if (settings.createAlbumFolder) {
1084                                                         if(settings.artName){
1085                                                                 filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,metadata.year,metadata.rtype))) + path.sep;
1086                                                         }else{
1087                                                                 filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,metadata.performerInfo,metadata.album,metadata.year,metadata.rtype))) + path.sep;
1088                                                         }
1089                                                 }
1090                                         } else if (settings.plName) {
1091                                                 filepath += antiDot(fixName(settings.plName)) + path.sep;
1092                                         } else if (settings.artName) {
1093                                                 filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,metadata.year,metadata.rtype))) + path.sep;
1094                                         }
1095                                         let writePath;
1096                                         if(track.format == 9){
1097                                                 writePath = filepath + filename + '.flac';
1098                                         }else{
1099                                                 writePath = filepath + filename + '.mp3';
1100                                         }
1101                                         if(track["LYRICS_SYNC_JSON"] && settings.syncedlyrics){
1102                                                 let lyricsbuffer = "";
1103                                                 for(let i=0;i<track["LYRICS_SYNC_JSON"].length;i++){
1104                                                         if(track["LYRICS_SYNC_JSON"][i].lrc_timestamp){
1105                                                                 lyricsbuffer += track["LYRICS_SYNC_JSON"][i].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
1106                                                         }else if(i+1 < track["LYRICS_SYNC_JSON"].length){
1107                                                                 lyricsbuffer += track["LYRICS_SYNC_JSON"][i+1].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
1108                                                         }
1109                                                 }
1110                                                 fs.outputFile(writePath.substring(0,writePath.lastIndexOf('.'))+".lrc",lyricsbuffer,function(){});
1111                                         }
1112                                         if (settings.createM3UFile && (settings.plName || settings.albName)) {
1113                                                 if (!settings.numplaylistbyalbum){
1114                                                         t.playlistData = [splitNumber(metadata.trackNumber,false)-1, filename + (track.format == 9 ? ".flac" : ".mp3")];
1115                                                 }else{
1116                                                         t.playlistData = [t.index, filename + (track.format == 9 ? ".flac" : ".mp3")];
1117                                                 }
1118                                         }else{
1119                                                 t.playlistData = [0,""];
1120                                         }
1121                                         if (fs.existsSync(writePath)) {
1122                                                 logger.info("Already downloaded: " + metadata.artist + ' - ' + metadata.title);
1123                                                 callback(null, t.playlistData);
1124                                                 return;
1125                                         }else{
1126                                                 logger.info('Downloading file to ' + writePath);
1127                                         }
1128                                         //Get image
1129                                         let temp4 = new Promise((resolve, reject)=>{
1130                                                 if (metadata.image) {
1131                                                         let imgPath;
1132                                                         //If its not from an album but a playlist.
1133                                                         if(!(settings.albName || settings.createAlbumFolder)){
1134                                                                 imgPath = coverArtFolder + fixName(metadata.ISRC) + ".jpg";
1135                                                         }else{
1136                                                                 if (settings.saveArtwork)
1137                                                                         imgPath = filepath + "folder.jpg";
1138                                                                 else
1139                                                                         imgPath = coverArtFolder + fixName(settings.artName+" - "+settings.albName) + ".jpg";
1140                                                         }
1141                                                         if(fs.existsSync(imgPath)){
1142                                                                 metadata.imagePath = (imgPath).replace(/\\/g, "/");
1143                                                                 logger.info("Starting the download process CODE:1");
1144                                                                 resolve();
1145                                                         }else{
1146                                                                 request.get(metadata.image, {encoding: 'binary'}, function(error,response,body){
1147                                                                         if(error){
1148                                                                                 logger.error(error.stack);
1149                                                                                 metadata.image = undefined;
1150                                                                                 metadata.imagePath = undefined;
1151                                                                                 return;
1152                                                                         }
1153                                                                         fs.outputFile(imgPath,body,'binary',function(err){
1154                                                                                 if(err){
1155                                                                                         logger.error(err.stack);
1156                                                                                 metadata.image = undefined;
1157                                                                                 metadata.imagePath = undefined;
1158                                                                                         return;
1159                                                                                 }
1160                                                                                 metadata.imagePath = (imgPath).replace(/\\/g, "/");
1161                                                                                 logger.info("Starting the download process CODE:2");
1162                                                                                 resolve();
1163                                                                         })
1164                                                                 });
1165                                                         }
1166                                                 }else{
1167                                                         metadata.image = undefined;
1168                                                         logger.info("Starting the download process CODE:3");
1169                                                         resolve();
1170                                                 }
1171                                         })
1172                                         temp4.then(()=>{
1173                                                 let tempPath = writePath+".temp";
1174                                                 logger.info("Downloading and decrypting");
1175                                                 Deezer.decryptTrack(tempPath, track, t.queueId, function (err) {
1176                                                         if (err && err.message == "aborted") {
1177                                                                 logger.info("Track got aborted");
1178                                                                 callback(null, t.playlistData);
1179                                                                 return;
1180                                                         }
1181                                                         if (err) {
1182                                                                 if (t.fallback){
1183                                                                         logger.error("Failed to download: " + metadata.artist + " - " + metadata.title+", falling on alternative");
1184                                                                         t.id = t.fallback
1185                                                                         t.fallback = 0
1186                                                                         downloadTrack(t, settings, metadata, callback);
1187                                                                 }else if(!t.searched){
1188                                                                         logger.warn("Failed to download track, searching for alternative");
1189                                                                         Deezer.track2ID(t.artist, t.name, data=>{
1190                                                                                 t.searched = true;
1191                                                                                 t.id = data.id;
1192                                                                                 t.artist = data.artist;
1193                                                                                 t.name = data.name;
1194                                                                                 downloadTrack(t, settings, null, function(err){
1195                                                                                         callback(err, `${t.id} | ${t.artist} - ${t.name}`);
1196                                                                                 });
1197                                                                         });
1198                                                                 }else{
1199                                                                         logger.error("Failed to download: " + metadata.artist + " - " + metadata.title);
1200                                                                         callback(err, `${t.id} | ${t.artist} - ${t.name}`)
1201                                                                 }
1202                                                                 return;
1203                                                         }
1204                                                         logger.info("Downloaded: " + metadata.artist + " - " + metadata.title);
1205                                                         metadata.artist = [];
1206                                                         artistArray = []
1207                                                         track['ARTISTS'].forEach(function(artist){
1208                                                                 artistArray.push(artist['ART_NAME']);
1209                                                         });
1210                                                         Array.from(new Set(artistArray)).forEach(function(artist){
1211                                                                 if(metadata.artist.indexOf(artist) == -1)
1212                                                                         metadata.artist.push(artist);
1213                                                         });
1214                                                         let separator = settings.multitagSeparator;
1215                                                         if (separator == "null") separator = String.fromCharCode(parseInt("\u0000",16));
1216                                                         if (track.format != 9) metadata.artist = metadata.artist.join(separator);
1217
1218                                                         if(track.format == 9){
1219                                                                 let flacComments = [
1220                                                                         'TITLE=' + metadata.title,
1221                                                                         'ALBUM=' + metadata.album,
1222                                                                         'ALBUMARTIST=' + metadata.performerInfo,
1223                                                                         'TRACKNUMBER=' + splitNumber(metadata.trackNumber,false),
1224                                                                         'DISCNUMBER=' + splitNumber(metadata.partOfSet,false),
1225                                                                         'TRACKTOTAL=' + splitNumber(metadata.trackNumber,true),
1226                                                                         'ITUNESADVISORY=' + metadata.explicit,
1227                                                                         'ISRC=' + metadata.ISRC
1228                                                                 ];
1229                                                                 metadata.artist.forEach(x=>{
1230                                                                         flacComments.push('ARTIST=' + x);
1231                                                                 })
1232                                                                 if (settings.partOfSet)
1233                                                                         flacComments.push('DISCTOTAL='+splitNumber(metadata.partOfSet,true))
1234                                                                 if(settings.extendedTags){
1235                                                                         flacComments.push(
1236                                                                                 'LENGTH=' + metadata.length,
1237                                                                                 'BARCODE=' + metadata.BARCODE
1238                                                                         );
1239                                                                 }
1240                                                                 if(metadata.unsynchronisedLyrics){
1241                                                                         flacComments.push('LYRICS='+metadata.unsynchronisedLyrics.lyrics);
1242                                                                 }
1243                                                                 if(metadata.genre){
1244                                                                         metadata.genre.forEach(x=>{
1245                                                                                 flacComments.push('GENRE=' + x);
1246                                                                         })
1247                                                                 }
1248                                                                 if(metadata.copyright){
1249                                                                         flacComments.push('COPYRIGHT=' + metadata.copyright);
1250                                                                 }
1251                                                                 if (0 < parseInt(metadata.year)) {
1252                                                                         flacComments.push('YEAR=' + metadata.year);
1253                                                                 }
1254                                                                 if (0 < parseInt(metadata.bpm)) {
1255                                                                         flacComments.push('BPM=' + metadata.bpm);
1256                                                                 }
1257                                                                 if(metadata.composer){
1258                                                                         flacComments.push('COMPOSER=' + metadata.composer);
1259                                                                 }
1260                                                                 if(metadata.publisher){
1261                                                                         flacComments.push('ORGANIZATION=' + metadata.publisher);
1262                                                                 }
1263                                                                 if(metadata.mixer){
1264                                                                         flacComments.push('MIXER=' + metadata.mixer);
1265                                                                 }
1266                                                                 if(metadata.author){
1267                                                                         flacComments.push('AUTHOR=' + metadata.author);
1268                                                                 }
1269                                                                 if(metadata.writer){
1270                                                                         flacComments.push('WRITER=' + metadata.writer);
1271                                                                 }
1272                                                                 if(metadata.engineer){
1273                                                                         flacComments.push('ENGINEER=' + metadata.engineer);
1274                                                                 }
1275                                                                 if(metadata.producer){
1276                                                                         flacComments.push('PRODUCER=' + metadata.producer);
1277                                                                 }
1278                                                                 if(metadata.trackgain){
1279                                                                         flacComments.push('REPLAYGAIN_TRACK_GAIN=' + metadata.trackgain);
1280                                                                 }
1281                                                                 const reader = fs.createReadStream(tempPath);
1282                                                                 const writer = fs.createWriteStream(writePath);
1283                                                                 let processor = new mflac.Processor({parseMetaDataBlocks: true});
1284                                                                 let vendor = 'reference libFLAC 1.2.1 20070917';
1285                                                                 let cover = null;
1286                                                                 if(metadata.imagePath){
1287                                                                         cover = fs.readFileSync(metadata.imagePath);
1288                                                                 }
1289                                                                 let mdbVorbisPicture;
1290                                                                 let mdbVorbisComment;
1291                                                                 processor.on('preprocess', (mdb) => {
1292                                                                         // Remove existing VORBIS_COMMENT and PICTURE blocks, if any.
1293                                                                         if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type) {
1294                                                                                 mdb.remove();
1295                                                                         } else if (mflac.Processor.MDB_TYPE_PICTURE === mdb.type) {
1296                                                                                 mdb.remove();
1297                                                                         }
1298                                                                         if (mdb.isLast) {
1299                                                                                 let res = 0;
1300                                                                                 if(settings.artworkSize.includes("1400")){
1301                                                                                         res = 1400;
1302                                                                                 }else if(settings.artworkSize.includes("1200")){
1303                                                                                         res = 1200;
1304                                                                                 }else if(settings.artworkSize.includes("1000")){
1305                                                                                         res = 1000;
1306                                                                                 }else if(settings.artworkSize.includes("800")){
1307                                                                                         res = 800;
1308                                                                                 }else if(settings.artworkSize.includes("500")){
1309                                                                                         res = 500;
1310                                                                                 }
1311                                                                                 if(cover){
1312                                                                                         mdbVorbisPicture = mflac.data.MetaDataBlockPicture.create(true, 3, 'image/jpeg', '', res, res, 24, 0, cover);
1313                                                                                 }
1314                                                                                 mdbVorbisComment = mflac.data.MetaDataBlockVorbisComment.create(false, vendor, flacComments);
1315                                                                                 mdb.isLast = false;
1316                                                                         }
1317                                                                 });
1318                                                                 processor.on('postprocess', (mdb) => {
1319                                                                         if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type && null !== mdb.vendor) {
1320                                                                                 vendor = mdb.vendor;
1321                                                                         }
1322                                                                         if (mdbVorbisPicture && mdbVorbisComment) {
1323                                                                                 processor.push(mdbVorbisComment.publish());
1324                                                                                 processor.push(mdbVorbisPicture.publish());
1325                                                                         }else if(mdbVorbisComment){
1326                                                                                 processor.push(mdbVorbisComment.publish());
1327                                                                         }
1328                                                                 });
1329                                                                 reader.on('end', () => {
1330                                                                         fs.remove(tempPath);
1331                                                                 });
1332                                                                 reader.pipe(processor).pipe(writer);
1333                                                         }else{
1334                                                                 const songBuffer = fs.readFileSync(tempPath);
1335                                                                 const writer = new ID3Writer(songBuffer);
1336                                                                 writer.setFrame('TIT2', metadata.title)
1337                                                                 .setFrame('TPE1', [metadata.artist])
1338                                                                 .setFrame('TALB', metadata.album)
1339                                                                 .setFrame('TPE2', metadata.performerInfo)
1340                                                                 .setFrame('TRCK', (settings.partOfSet ? metadata.trackNumber : splitNumber(metadata.trackNumber,false)))
1341                                                                 .setFrame('TPOS', (settings.partOfSet ? metadata.partOfSet : splitNumber(metadata.partOfSet,false)))
1342                                                                 .setFrame('TSRC', metadata.ISRC);
1343                                                                 if (settings.extendedTags){
1344                                                                         writer.setFrame('TLEN', metadata.length)
1345                                                                         .setFrame('TXXX', {
1346                                                                                 description: 'BARCODE',
1347                                                                                 value: metadata.BARCODE
1348                                                                         })
1349                                                                 }
1350                                                                 if(metadata.imagePath){
1351                                                                         const coverBuffer = fs.readFileSync(metadata.imagePath);
1352                                                                         writer.setFrame('APIC', {
1353                                                                                 type: 3,
1354                                                                                 data: coverBuffer,
1355                                                                                 description: ''
1356                                                                         });
1357                                                                 }
1358                                                                 if(metadata.unsynchronisedLyrics){
1359                                                                         writer.setFrame('USLT', metadata.unsynchronisedLyrics);
1360                                                                 }
1361                                                                 if(metadata.publisher){
1362                                                                         writer.setFrame('TPUB', metadata.publisher);
1363                                                                 }
1364                                                                 if(metadata.genre){
1365                                                                         writer.setFrame('TCON', [metadata.genre]);
1366                                                                 }
1367                                                                 if(metadata.copyright){
1368                                                                         writer.setFrame('TCOP', metadata.copyright);
1369                                                                 }
1370                                                                 if (0 < parseInt(metadata.year)) {
1371                                                                         writer.setFrame('TYER', metadata.year);
1372                                                                 }
1373                                                                 if (0 < parseInt(metadata.bpm)) {
1374                                                                         writer.setFrame('TBPM', metadata.bpm);
1375                                                                 }
1376                                                                 if(metadata.composer){
1377                                                                         writer.setFrame('TCOM', [metadata.composer]);
1378                                                                 }
1379                                                                 if(metadata.trackgain){
1380                                                                         writer.setFrame('TXXX', {
1381                                                                                 description: 'REPLAYGAIN_TRACK_GAIN',
1382                                                                                 value: metadata.trackgain
1383                                                                         });
1384                                                                 }
1385                                                                 writer.addTag();
1386                                                                 const taggedSongBuffer = Buffer.from(writer.arrayBuffer);
1387                                                                 fs.writeFileSync(writePath, taggedSongBuffer);
1388                                                                 fs.remove(tempPath);
1389                                                         }
1390                                                         callback(null, t.playlistData);
1391                                                 })
1392                                         })
1393                                 })
1394                         })
1395                 })
1396         }
1397
1398         function checkIfAlreadyInQueue(id) {
1399                 let exists = false;
1400                 Object.keys(socket.downloadQueue).forEach(x=>{
1401                         if (socket.downloadQueue[x].id == id) {
1402                                 exists = socket.downloadQueue[i].queueId;
1403                         }
1404                 });
1405                 if (socket.currentItem && (socket.currentItem.id == id)) {
1406                         exists = socket.currentItem.queueId;
1407                 }
1408                 return exists;
1409         }
1410 });
1411
1412 // Helper functions
1413
1414 /**
1415  * Updates individual parameters in the settings file
1416  * @param config
1417  * @param value
1418  */
1419 function updateSettingsFile(config, value) {
1420         configFile.userDefined[config] = value;
1421
1422         fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
1423                 if (err) return;
1424                 logger.info("Settings updated");
1425
1426                 // FIXME: Endless Loop, due to call from initFolders()...crashes soon after startup
1427                 // initFolders();
1428         });
1429 }
1430
1431 function fixName (txt) {
1432   const regEx = /[\0\/\\:*?"<>|]/g;
1433   return txt.replace(regEx, '_');
1434 }
1435
1436 function antiDot(str){
1437         while(str[str.length-1] == "." || str[str.length-1] == " " || str[str.length-1] == "\n"){
1438                 str = str.substring(0,str.length-1);
1439         }
1440         if(str.length < 1){
1441                 str = "dot";
1442         }
1443         return fixName(str);
1444 }
1445
1446 /**
1447  * Initialize the temp folder for covers and main folder for downloads
1448  */
1449 function initFolders() {
1450         // Check if main folder exists
1451         if (!fs.existsSync(mainFolder)) {
1452                 mainFolder = defaultDownloadDir;
1453                 updateSettingsFile('downloadLocation', defaultDownloadDir);
1454         }
1455         //fs.removeSync(coverArtFolder);
1456         fs.ensureDirSync(coverArtFolder);
1457 }
1458
1459 /**
1460  * Creates the name of the tracks replacing wildcards to correct metadata
1461  * @param metadata
1462  * @param filename
1463  * @param playlist
1464  * @returns {XML|string|*}
1465  */
1466 function settingsRegex(metadata, filename, playlist) {
1467         filename = filename.replace(/%title%/g, metadata.title);
1468         filename = filename.replace(/%album%/g, metadata.album);
1469         filename = filename.replace(/%artist%/g, metadata.artist);
1470         filename = filename.replace(/%year%/g, metadata.year);
1471         if(typeof metadata.trackNumber != 'undefined'){
1472                 if(configFile.userDefined.padtrck){
1473                          filename = filename.replace(/%number%/g, pad(splitNumber(metadata.trackNumber, false), splitNumber(metadata.trackNumber, true)));
1474                 }else{
1475                         filename = filename.replace(/%number%/g, splitNumber(metadata.trackNumber, false));
1476                 }
1477         } else {
1478                 filename = filename.replace(/%number%/g, '');
1479         }
1480         return filename;
1481 }
1482
1483 /**
1484  * Creates the name of the albums folder replacing wildcards to correct metadata
1485  * @param metadata
1486  * @param foldername
1487  * @returns {XML|string|*}
1488  */
1489 function settingsRegexAlbum(foldername, artist, album, year, rtype) {
1490         foldername = foldername.replace(/%album%/g, album);
1491         foldername = foldername.replace(/%artist%/g, artist);
1492         foldername = foldername.replace(/%year%/g, year);
1493         foldername = foldername.replace(/%type%/g, rtype);
1494         return foldername;
1495 }
1496
1497 /**
1498  * I really don't understand what this does ... but it does something
1499  * @param str
1500  * @param max
1501  * @returns {String|string|*}
1502  */
1503 function pad(str, max) {
1504         str = str.toString();
1505         max = max.toString();
1506         return str.length < max.length || str.length == 1 ? pad("0" + str, max) : str;
1507 }
1508
1509 /**
1510  * Splits the %number%
1511  * @param string str
1512  * @return string
1513  */
1514 function splitNumber(str,total){
1515         str = str.toString();
1516         let i = str.indexOf("/");
1517         if(total && i > 0){
1518                 return str.slice(i+1, str.length);
1519         }else if(i > 0){
1520                 return str.slice(0, i);
1521         }else{
1522                 return str;
1523         }
1524         return i > 0 ? str.slice(0, i) : str;
1525 }
1526
1527 function slimDownTrackInfo(trackOld){
1528         let track = {};
1529         track['SNG_ID'] = trackOld["SNG_ID"]
1530         track['ARTISTS'] = trackOld["ARTISTS"]
1531         track["ALB_ID"] = trackOld["ALB_ID"]
1532         track["ALB_PICTURE"] = trackOld["ALB_PICTURE"]
1533         track["ALB_TITLE"] = trackOld["ALB_TITLE"]
1534         track["ART_NAME"] = trackOld["ART_NAME"]
1535         track["BPM"] = trackOld["BPM"]
1536         track["COPYRIGHT"] = trackOld["COPYRIGHT"]
1537         track["DISK_NUMBER"] = trackOld["DISK_NUMBER"]
1538         track["DURATION"] = trackOld["DURATION"]
1539         track["EXPLICIT_LYRICS"] = trackOld["EXPLICIT_LYRICS"]
1540         track["GAIN"] = trackOld["GAIN"]
1541         track["ISRC"] = trackOld["ISRC"]
1542         track["LYRICS_SYNC_JSON"] = trackOld["LYRICS_SYNC_JSON"]
1543         track["LYRICS_TEXT"] = trackOld["LYRICS_TEXT"]
1544         track["PHYSICAL_RELEASE_DATE"] = trackOld["PHYSICAL_RELEASE_DATE"]
1545         track["SNG_CONTRIBUTORS"] = trackOld["SNG_CONTRIBUTORS"]
1546         track["SNG_TITLE"] = trackOld["SNG_TITLE"]
1547         track["TRACK_NUMBER"] = trackOld["TRACK_NUMBER"]
1548         track["VERSION"] = trackOld["VERSION"]
1549         track["FILESIZE_FLAC"] = trackOld["FILESIZE_FLAC"]
1550         track["FILESIZE_MP3_320"] = trackOld["FILESIZE_MP3_320"]
1551         track["FILESIZE_MP3_256"] = trackOld["FILESIZE_MP3_256"]
1552         track["FILESIZE_MP3_128"] = trackOld["FILESIZE_MP3_128"]
1553         track["FALLBACK"] = trackOld["FALLBACK"]
1554         track.downloadUrl = trackOld.downloadUrl
1555         track.format = trackOld.format
1556         return track
1557 }
1558
1559 function slimDownAlbumInfo(ajsonOld){
1560         let ajson = {};
1561         ajson.artist = {}
1562         ajson.artist.name = ajsonOld.artist.name
1563         ajson.nb_tracks = ajsonOld.nb_tracks
1564         ajson.upc = ajsonOld.upc
1565         ajson.record_type = ajsonOld.record_type
1566         ajson.label = ajsonOld.label
1567         ajson.genres = ajsonOld.genres
1568         ajson.release_date = ajsonOld.release_date
1569         ajson.tracks = {
1570                 data: ajsonOld.tracks.data.map(x=>{
1571                         return {id: x.id};
1572                 })
1573         }
1574         ajson.tracks.total = ajsonOld.tracks.total
1575         return ajson
1576 }
1577
1578 function parseMetadata(track, ajson, totalDiskNumber, settings, position, altmetadata){
1579         let metadata;
1580         if (track["VERSION"]) track["SNG_TITLE"] += " " + track["VERSION"];
1581         if(altmetadata){
1582                 metadata = altmetadata;
1583                 if(track["LYRICS_TEXT"] && !metadata.unsynchronisedLyrics){
1584                         metadata.unsynchronisedLyrics = {
1585                                 description: "",
1586                                 lyrics: track["LYRICS_TEXT"]
1587                         };
1588                 }
1589         }else{
1590                 metadata = {
1591                         title: track["SNG_TITLE"],
1592                         artist: track["ART_NAME"],
1593                         album: track["ALB_TITLE"],
1594                         performerInfo: ajson.artist.name,
1595                         trackNumber: track["TRACK_NUMBER"] + "/" + ajson.nb_tracks,
1596                         partOfSet: track["DISK_NUMBER"],
1597                         explicit: track["EXPLICIT_LYRICS"],
1598                         ISRC: track["ISRC"],
1599                 };
1600                 if (settings.extendedTags){
1601                         metadata.length = track["DURATION"];
1602                         metadata.BARCODE = ajson.upc;
1603                         metadata.rtype = ajson.record_type;
1604                         if(track["COPYRIGHT"]){
1605                                 metadata.copyright = track["COPYRIGHT"];
1606                         }
1607                         if(track["SNG_CONTRIBUTORS"]){
1608                                 if(track["SNG_CONTRIBUTORS"].composer){
1609                                         let composertag = "";
1610                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].composer.length; i++) {
1611                                                 composertag += track["SNG_CONTRIBUTORS"].composer[i] + ", ";
1612                                         }
1613                                         metadata.composer = composertag.substring(0,composertag.length-2);
1614                                 }
1615                                 if(track["SNG_CONTRIBUTORS"].musicpublisher){
1616                                         let publishertag = "";
1617                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].musicpublisher.length; i++) {
1618                                                 publishertag += track["SNG_CONTRIBUTORS"].musicpublisher[i] + ", ";
1619                                         }
1620                                         metadata.publisher = publishertag.substring(0,publishertag.length-2);
1621                                 }
1622                                 if(track["SNG_CONTRIBUTORS"].producer){
1623                                         let producertag = "";
1624                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].producer.length; i++) {
1625                                                 producertag += track["SNG_CONTRIBUTORS"].producer[i] + ", ";
1626                                         }
1627                                         metadata.producer = producertag.substring(0,producertag.length-2);
1628                                 }
1629                                 if(track["SNG_CONTRIBUTORS"].engineer){
1630                                         let engineertag = "";
1631                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].engineer.length; i++) {
1632                                                 engineertag += track["SNG_CONTRIBUTORS"].engineer[i] + ", ";
1633                                         }
1634                                         metadata.engineer = engineertag.substring(0,engineertag.length-2);
1635                                 }
1636                                 if(track["SNG_CONTRIBUTORS"].writer){
1637                                         let writertag = "";
1638                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].writer.length; i++) {
1639                                                 writertag += track["SNG_CONTRIBUTORS"].writer[i] + ", ";
1640                                         }
1641                                         metadata.writer = writertag.substring(0,writertag.length-2);
1642                                 }
1643                                 if(track["SNG_CONTRIBUTORS"].author){
1644                                         let authortag = "";
1645                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].author.length; i++) {
1646                                                 authortag += track["SNG_CONTRIBUTORS"].author[i] + ", ";
1647                                         }
1648                                         metadata.author = authortag.substring(0,authortag.length-2);
1649                                 }
1650                                 if(track["SNG_CONTRIBUTORS"].mixer){
1651                                         let mixertag = "";
1652                                         for (let i = 0; i < track["SNG_CONTRIBUTORS"].mixer.length; i++) {
1653                                                 mixertag += track["SNG_CONTRIBUTORS"].mixer[i] + ", ";
1654                                         }
1655                                         metadata.mixer = mixertag.substring(0,mixertag.length-2);
1656                                 }
1657                         }
1658                         if(track["LYRICS_TEXT"]){
1659                                 metadata.unsynchronisedLyrics = {
1660                                         description: "",
1661                                         lyrics: track["LYRICS_TEXT"]
1662                                 };
1663                         }
1664                         if (track["GAIN"]) {
1665                                 metadata.trackgain = track["GAIN"];
1666                         }
1667                 }
1668                 if(ajson.label && !metadata.publisher){
1669                         metadata.publisher = ajson.label;
1670                 }
1671                 if (0 < parseInt(track["BPM"])) {
1672                         metadata.bpm = track["BPM"];
1673                 }
1674                 if(ajson.genres && ajson.genres.data[0] && ajson.genres.data[0].name){
1675                         metadata.genre = [];
1676                         genreArray = [];
1677                         ajson.genres.data.forEach(function(genre){
1678                                 genreArray.push(genre.name);
1679                         });
1680                         Array.from(new Set(genreArray)).forEach(function(genre){
1681                                 if(metadata.genre.indexOf(genre) == -1)
1682                                         metadata.genre.push(genre);
1683                         });
1684                         let separator = settings.multitagSeparator;
1685                         if (separator == "null") separator = String.fromCharCode(parseInt("\u0000",16))
1686                         if (track.format != 9) metadata.genre = metadata.genre.join(separator);
1687                 }
1688                 if (track["ALB_PICTURE"]) {
1689                         metadata.image = Deezer.albumPicturesHost + track["ALB_PICTURE"] + settings.artworkSize;
1690                 }
1691                 if(track["PHYSICAL_RELEASE_DATE"]){
1692                         metadata.year = track["PHYSICAL_RELEASE_DATE"].slice(0, 4);
1693                 }else if (ajson.release_date) {
1694                         metadata.year = ajson.release_date.slice(0, 4);
1695                 }
1696                 if(settings.plName && !(settings.createArtistFolder || settings.createAlbumFolder) && !settings.numplaylistbyalbum){
1697                         metadata.trackNumber = (position+1).toString() + "/" + settings.playlist.fullSize;
1698                         metadata.partOfSet = "1/1";
1699                 }
1700                 if (totalDiskNumber){
1701                         metadata.partOfSet += "/"+totalDiskNumber
1702                 }
1703         }
1704         return metadata;
1705 }
1706
1707 process.on('unhandledRejection', function (err) {
1708         logger.error(err.stack);
1709 });
1710 // Show crash error in console for debugging
1711 process.on('uncaughtException', function (err) {
1712         logger.error(err.stack);
1713 });
1714
1715 // Exporting vars
1716 module.exports.mainFolder = mainFolder;
1717 module.exports.defaultSettings = defaultSettings;
1718 module.exports.defaultDownloadDir = defaultDownloadDir;