Updated README.md
[DeezloaderRemix.git] / app / app.js
index 5e845843665da054d1a35b268f03016d38fbe3c0..f3c545159f28f055bce14ff3dcc53049c4d1d228 100644 (file)
 /*
- *  _____                    _                    _
- * |  __ \                  | |                  | |
- * | |  | |  ___   ___  ____| |  ___    __ _   __| |  ___  _ __
- * | |  | | / _ \ / _ \|_  /| | / _ \  / _` | / _` | / _ \| '__|
- * | |__| ||  __/|  __/ / / | || (_) || (_| || (_| ||  __/| |
- * |_____/  \___| \___|/___||_| \___/  \__,_| \__,_| \___||_|
- *
- *
- *
- *  Original work by ZzMTV <https://boerse.to/members/zzmtv.3378614/>
- * */
-
-const express = require('express');
-const app = express();
-const server = require('http').createServer(app);
-const mflac = require('./lib/flac-metadata');
-const io = require('socket.io').listen(server, {log: false, wsEngine: 'ws'});
-const fs = require('fs-extra');
-const async = require('async');
-const request = require('requestretry').defaults({maxAttempts: 2147483647, retryDelay: 1000, timeout: 8000});
-const os = require('os');
-const ID3Writer = require('./lib/browser-id3-writer');
-const Deezer = require('./deezer-api');
-const path = require('path');
-const crypto = require('crypto');
-const logger = require('./logger.js');
-const Spotify = require('spotify-web-api-node');
-const authCredentials = require('./authCredentials.js')
+*   _____                _                 _             _____                _
+*  |  __ \              | |               | |           |  __ \              (_)
+*  | |  | | ___  ___ ___| | ___   __ _  __| | ___ _ __  | |__) |___ _ __ ___  ___  __
+*  | |  | |/ _ \/ _ \_  / |/ _ \ / _` |/ _` |/ _ \ '__| |  _  // _ \ '_ ` _ \| \ \/ /
+*  | |__| |  __/  __// /| | (_) | (_| | (_| |  __/ |    | | \ \  __/ | | | | | |>  <
+*  |_____/ \___|\___/___|_|\___/ \__,_|\__,_|\___|_|    |_|  \_\___|_| |_| |_|_/_/\_\
+*
+**/
+
+// Server stuff
+const express = require('express')
+const app = express()
+const server = require('http').createServer(app)
+const io = require('socket.io').listen(server, {log: false, wsEngine: 'ws'})
+// Music tagging stuff
+const mflac = require('./lib/flac-metadata')
+const ID3Writer = require('./lib/browser-id3-writer')
+const deezerApi = require('./lib/deezer-api')
+const spotifyApi = require('spotify-web-api-node')
+// App stuff
+const fs = require('fs-extra')
+const async = require('async')
+const request = require('request-promise')
+const requestOld = require('request')
+const os = require('os')
+const path = require('path')
+const logger = require('./utils/logger.js')
 const queue = require('queue')
+const localpaths = require('./utils/localpaths.js')
+const package = require('./package.json')
+const stq = require('sequential-task-queue')
 
-// Load Config File
-var userdata = "";
-var homedata = "";
-if(process.env.APPDATA){
-       homedata = os.homedir();
-       userdata = process.env.APPDATA + path.sep + "Deezloader Remix" + path.sep;
-}else if(process.platform == "darwin"){
-       homedata = os.homedir();
-       userdata = homedata + '/Library/Application Support/Deezloader Remix/';
-}else if(process.platform == "android"){
-       homedata = os.homedir() + "/storage/shared";
-       userdata = homedata + "/Deezloader Remix/";
-}else{
-       homedata = os.homedir();
-       userdata = homedata + '/.config/Deezloader Remix/';
+// First run, create config file
+if(!fs.existsSync(localpaths.user+"config.json")){
+       fs.outputFileSync(localpaths.user+"config.json",fs.readFileSync(__dirname+path.sep+"default.json",'utf8'))
 }
 
-if(!fs.existsSync(userdata+"config.json")){
-       fs.outputFileSync(userdata+"config.json",fs.readFileSync(__dirname+path.sep+"default.json",'utf8'));
-}
-
-var spotifyApi = new Spotify(authCredentials);
-
 // Main Constants
-const configFileLocation = userdata+"config.json";
-const autologinLocation = userdata+"autologin";
-const coverArtFolder = os.tmpdir() + path.sep + 'deezloader-imgs' + path.sep;
-const defaultDownloadDir = homedata + path.sep + "Music" + path.sep + 'Deezloader' + path.sep;
-const defaultSettings = require('./default.json').userDefined;
+// Files
+const configFileLocation = localpaths.user+"config.json"
+// Folders
+const coverArtFolder = os.tmpdir() + path.sep + 'deezloader-imgs' + path.sep
+const defaultDownloadFolder = localpaths.user + 'Deezloader Music' + path.sep
+// Default settings
+const defaultSettings = require('./default.json').userDefined
+// Spotify Files
+const spotifySupport = fs.existsSync(localpaths.user+"authCredentials.js")
+if (spotifySupport){
+       var authCredentials = require(localpaths.user+'authCredentials.js')
+       var Spotify = new spotifyApi(authCredentials)
+}
 
 // Setup the folders START
-var mainFolder = defaultDownloadDir;
+var mainFolder = defaultDownloadFolder
 
-// Settings update fix
-var configFile = require(userdata+path.sep+"config.json");
+// See if all settings are there after update
+var configFile = require(localpaths.user+path.sep+"config.json");
 for (let x in defaultSettings){
        if (typeof configFile.userDefined[x] != typeof defaultSettings[x]){
                configFile.userDefined[x] = defaultSettings[x]
        }
 }
-
+// Set default download folder if not userDefined
 if (configFile.userDefined.downloadLocation != "") {
-       mainFolder = configFile.userDefined.downloadLocation;
+       mainFolder = configFile.userDefined.downloadLocation
 }
 
 initFolders();
-// END
-
-// Route and Create server
-app.use('/', express.static(__dirname + '/public/'));
-server.listen(configFile.serverPort);
-logger.info('Server is running @ localhost:' + configFile.serverPort);
-
-//Autologin encryption/decryption
-var ekey = "62I9smDurjvfOdn2JhUdi99yeoAhxikw";
-
-function alencrypt(input) {
-       let iv = crypto.randomBytes(16);
-       let data = new Buffer(input).toString('binary');
-       key = new Buffer(ekey, "utf8");
-       let cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
-       let encrypted;
-       encrypted =  cipher.update(data, 'utf8', 'binary') +  cipher.final('binary');
-       let encoded = new Buffer(iv, 'binary').toString('hex') + new Buffer(encrypted, 'binary').toString('hex');
-
-       return encoded;
-}
 
-function aldecrypt(encoded) {
-       let combined = new Buffer(encoded, 'hex');
-       key = new Buffer(ekey, "utf8");
-       // Create iv
-       let iv = new Buffer(16);
-       combined.copy(iv, 0, 0, 16);
-       edata = combined.slice(16).toString('binary');
-       // Decipher encrypted data
-       let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
-       let decrypted, plaintext;
-       plaintext = (decipher.update(edata, 'binary', 'utf8') + decipher.final('utf8'));
-
-       return plaintext;
-}
+// Route and create server
+app.use('/', express.static(__dirname + '/public/'))
+server.listen(configFile.serverPort)
+logger.info('Server is running @ localhost:' + configFile.serverPort)
 
 // START sockets clusterfuck
-io.sockets.on('connection', function (socket) {
-       socket.downloadQueue = {};
-       socket.currentItem = null;
-       socket.lastQueueId = null;
-       socket.trackQueue = queue({
+io.sockets.on('connection', function (s) {
+       logger.info("Connection recived!")
+
+       // Check for updates
+       request({
+               url: "https://notabug.org/RemixDevs/DeezloaderRemix/raw/master/update.json",
+               json: true
+       })
+       .then(body=>{
+               logger.info("Checking for updates")
+               let [currentVersion_MAJOR, currentVersion_MINOR, currentVersion_PATCH] = package.version.split(".")
+               let [lastVersion_MAJOR, lastVersion_MINOR, lastVersion_PATCH] = body.version.split(".")
+               if (
+                       parseInt(lastVersion_MAJOR) > parseInt(currentVersion_MAJOR) ||
+                       parseInt(lastVersion_MINOR) > parseInt(currentVersion_MINOR) ||
+                       parseInt(lastVersion_PATCH) > parseInt(currentVersion_PATCH))
+               {
+                       logger.info("Update Available")
+                       s.emit("message", {title: `Version ${lastVersion_MAJOR}.${lastVersion_MINOR}.${lastVersion_PATCH} is available!`, msg: body.changelog})
+               }
+       })
+       .catch(error=>{
+               logger.error(`UpdateCheck failed: ${error.stack ? error.stack : error}`)
+       })
+
+       // Connection dependet variables
+       s.Deezer = new deezerApi()
+       s.dqueue = new stq.SequentialTaskQueue()
+       s.downloadQueue = {}
+       s.trackQueue = queue({
                autostart: true
+       })
+       s.trackQueue.concurrency = configFile.userDefined.queueConcurrency
+
+       // Function for logging in
+       s.on("login", async function (username, password, autologin) {
+               try{
+                       logger.info("Logging in");
+                       await s.Deezer.login(username, password)
+                       s.emit("login", {user: s.Deezer.user})
+                       logger.info("Logged in successfully")
+                       if (autologin){
+                               // Save session login so next time login is not needed
+                               // This is the same method used by the official website
+                               s.emit('getCookies', s.Deezer.getCookies())
+                       }
+               }catch(err){
+                       s.emit("login", {error: err.message})
+                       logger.error(`Login failed: ${err.message}`)
+               }
        });
-       socket.trackQueue.concurrency = configFile.userDefined.queueConcurrency;
 
-       socket.on("login", function (username, password, autologin) {
-               Deezer.init(username, password, function (err) {
-                       if(err){
-                               socket.emit("login", {error: err.message});
-                               logger.error("Failed to login, "+err.stack);
-                       }else{
-                               if(autologin){
-                                       let data = username + "\n" + password;
-                                       fs.outputFile(autologinLocation, alencrypt(data) , function(){
-                                               if(!err){
-                                                       logger.info("Added autologin successfully");
-                                               }else{
-                                                       logger.info("Failed to add autologin file");
+       // Function for autologin
+       s.on("autologin", async function(jar, email){
+               try{
+      await s.Deezer.loginViaCookies(jar, email)
+                       s.emit('login', {user: s.Deezer.user})
+    }catch(err){
+      s.emit('login', {error: err.message})
+                       logger.error(`Autologin failed: ${err.message}`)
+      return
+    }
+       })
+
+       // Function for logout
+       s.on("logout", function(){
+               logger.info("Logged out")
+               // Creating new object to clear the cookies
+               s.Deezer = new deezerApi()
+               return
+       })
+
+       // Returns list of charts available
+       s.on("getChartsCountryList", async function (data) {
+               try{
+                       let charts = await s.Deezer.legacyGetChartsTopCountry()
+                       charts = charts.data || []
+                       let countries = []
+                       for (let i = 0; i < charts.length; i++) {
+                               let obj = {
+                                       country: charts[i].title.replace("Top ", ""),
+                                       picture_small: charts[i].picture_small,
+                                       picture_medium: charts[i].picture_medium,
+                                       picture_big: charts[i].picture_big,
+                                       playlistId: charts[i].id
+                               }
+                               countries.push(obj)
+                       }
+                       s.emit("getChartsCountryList", {countries: countries, selected: data.selected})
+               }catch(err){
+                       logger.error(`getChartsCountryList failed: ${err.stack}`)
+                       return
+               }
+       })
+
+       // Returns chart tracks from Playlist ID
+       async function getChartsTrackListById(playlistId){
+               if (typeof playlistId === 'undefined') {
+                       s.emit("getChartsTrackListByCountry", {err: "Can't find that playlist"})
+                       return
+               }
+               try{
+                       let tracks = await s.Deezer.legacyGetPlaylistTracks(playlistId)
+                       s.emit("getChartsTrackListByCountry", {
+                               playlistId: playlistId,
+                               tracks: tracks.data
+                       })
+               }catch(err){
+                       s.emit("getChartsTrackListByCountry", {err: err})
+                       logger.error(`getChartsTrackListById failed: ${err.stack}`)
+                       return
+               }
+       }
+
+       // Returns chart tracks from country name
+       async function getChartsTrackListByCountry(country){
+               if (typeof country === 'undefined') {
+                       s.emit("getChartsTrackListByCountry", {err: "No country passed"})
+                       return
+               }
+               try{
+                       let charts = await s.Deezer.legacyGetChartsTopCountry()
+                       charts = charts.data || []
+                       let countries = []
+                       for (let i = 0; i < charts.length; i++) {
+                               countries.push(charts[i].title.replace("Top ", ""))
+                       }
+                       if (countries.indexOf(country) == -1) {
+                               s.emit("getChartsTrackListByCountry", {err: "Country not found"})
+                               return
+                       }
+                       let playlistId = charts[countries.indexOf(country)].id
+                       await getChartsTrackListById(playlistId)
+               }catch(err){
+                       logger.error(`getChartsTrackListByCountry failed: ${err.stack}`)
+                       return
+               }
+       }
+       s.on("getChartsTrackListByCountry", function (data) {getChartsTrackListByCountry(data.country)})
+
+       // Returns list of playlists
+       async function getMyPlaylistList(){
+               try{
+                       logger.info("Loading Personal Playlists")
+                       let data = await s.Deezer.legacyGetUserPlaylists(s.Deezer.user.id)
+                       data = data.data || []
+                       let playlists = []
+                       for (let i = 0; i < data.length; i++) {
+                               let obj = {
+                                       title: data[i].title,
+                                       image: data[i].picture_small,
+                                       songs: data[i].nb_tracks,
+                                       link: data[i].link
+                               }
+                               playlists.push(obj)
+                       }
+                       if (configFile.userDefined.spotifyUser && spotifySupport){
+                               try{
+                                       let creds = await Spotify.clientCredentialsGrant()
+                                       Spotify.setAccessToken(creds.body['access_token'])
+                                       let first = true
+                                       let offset = 0
+                                       do{
+                                               let data = await Spotify.getUserPlaylists(configFile.userDefined.spotifyUser, {fields: "items(images,name,owner.id,tracks.total,uri),total", offset: offset*20})
+                                               if (first){
+                                                       var total = data.body.total
+                                                       var numPages=Math.floor((total-1)/20)
+                                                       var playlistList = new Array(total)
+                                                       first = false
                                                }
-                                       });
+                                               data.body.items.forEach((playlist, i) => {
+                                                       playlistList[(offset*20)+i] = {
+                                                               title: playlist.name,
+                                                               image: (playlist.images[0] ? playlist.images[0].url : ""),
+                                                               songs: playlist.tracks.total,
+                                                               link: playlist.uri,
+                                                               spotify: true
+                                                       }
+                                               })
+                                               offset++
+                                       }while(offset<=numPages)
+                                       playlists = playlists.concat(playlistList)
+                               }catch(err){
+                                       logger.error(`Spotify playlist failed loading: ${err}`)
                                }
-                               socket.emit("login", {username: Deezer.userName, picture: Deezer.userPicture});
-                               logger.info("Logged in successfully");
                        }
-               });
-       });
+                       logger.info(`Loaded ${playlists.length} Playlist${playlists.length>1 ? "s" : ""}`)
+                       s.emit("getMyPlaylistList", {playlists: playlists})
+               }catch(err){
+                       logger.error(`getMyPlaylistList failed: ${err}`)
+                       return
+               }
+       }
+       s.on("getMyPlaylistList", function (d) {getMyPlaylistList()})
+
+       // Returns search results from a query
+       s.on("search", async function (data) {
+               data.type = data.type || "track"
+               if (["track", "playlist", "album", "artist"].indexOf(data.type) == -1) data.type = "track"
+
+               // Remove "feat."  "ft." and "&" (causes only problems)
+               data.text = data.text
+                       .replace(/ feat[\.]? /g, " ")
+                       .replace(/ ft[\.]? /g, " ")
+                       .replace(/\(feat[\.]? /g, " ")
+                       .replace(/\(ft[\.]? /g, " ")
+                       .replace(/\&/g, "")
+                       .replace(/–/g, "-")
+                       .replace(/—/g, "-")
+
+               try {
+                       let searchObject = await s.Deezer.legacySearch(encodeURIComponent(data.text), data.type)
+                       s.emit("search", {type: data.type, items: searchObject.data})
+               } catch (err) {
+                       s.emit("search", {type: data.type, items: []})
+                       logger.error(`search failed: ${err.stack}`)
+                       return
+               }
+       })
 
-       socket.on("autologin", function(){
-               fs.readFile(autologinLocation, function(err, data){
-                       if(err){
-                               logger.info("No auto login found");
-                               return;
+       // Returns list of tracks from an album/playlist or the list of albums from an artist
+       s.on("getTrackList", async function (data) {
+               if (!data.type || (["playlist", "album", "artist", "spotifyplaylist"].indexOf(data.type) == -1) || !data.id) {
+                       s.emit("getTrackList", {err: -1, response: {}, id: data.id, reqType: data.type})
+                       return
+               }
+               if (data.type == 'artist') {
+                       try{
+                               let response = await s.Deezer.legacyGetArtistAlbums(data.id)
+                               s.emit("getTrackList", {response: response, id: data.id, reqType: data.type})
+                       }catch(err){
+                               s.emit("getTrackList", {err: "wrong artist id", response: {}, id: data.id, reqType: data.type})
+                               logger.error(`getTrackList failed: ${err.stack}`)
+                               return
                        }
+               }else if(data.type == "spotifyplaylist" && spotifySupport){
                        try{
-                               var fdata = aldecrypt(data.toString('utf8'));
-
-                       }catch(e){
-                               logger.warn("Invalid autologin file, deleting");
-                               fs.unlink(autologinLocation,function(){
-                               });
-                               return;
+                               let creds = await Spotify.clientCredentialsGrant()
+                               Spotify.setAccessToken(creds.body.access_token)
+                               let first = true
+                               let offset = 0
+                               do{
+                                       let resp = await Spotify.getPlaylistTracks(data.id, {fields: "items(track(artists,name,duration_ms,preview_url,explicit)),total", offset: offset*100})
+                                       if (first){
+                                               var numPages=Math.floor((resp.body.total-1)/100)
+                                               var response = new Array(resp.body.total)
+                                               first = false
+                                       }
+                                       resp.body.items.forEach((t, index) => {
+                                               response[index+offset*100]={
+                                                       explicit_lyrics: t.track.explicit,
+                                                       preview: t.track.preview_url,
+                                                       title: t.track.name,
+                                                       artist: {
+                                                               name: t.track.artists[0].name
+                                                       },
+                                                       duration: Math.floor(t.track.duration_ms/1000)
+                                               }
+                                       })
+                                       offset++
+                               }while(offset<=numPages)
+                               s.emit("getTrackList", {response: {'data': response}, id: data.id, reqType: data.type})
+                       }catch(err){
+                               logger.error(`getTrackList failed: ${err.stack}`)
                        }
-                       fdata = fdata.split('\n');
-                       socket.emit("autologin",fdata[0],fdata[1]);
-               });
+               }else{
+                       let reqType = data.type.charAt(0).toUpperCase() + data.type.slice(1)
+                       try{
+                               let response = await s.Deezer["legacyGet" + reqType + "Tracks"](data.id)
+                               s.emit("getTrackList", {response: response, id: data.id, reqType: data.type})
+                       }catch(err){
+                               s.emit("getTrackList", {err: "wrong id "+reqType, response: {}, id: data.id, reqType: data.type})
+                               logger.error(`getTrackList failed: ${err.stack}`)
+                               return
+                       }
+               }
+       })
+
+       // Sends settings saved by the user to the frontend
+       s.on("getUserSettings", function () {
+               let settings = configFile.userDefined
+               if (!settings.downloadLocation) {
+                       settings.downloadLocation = mainFolder
+               }
+               s.emit('getUserSettings', {settings: settings})
        });
 
-       socket.on("logout", function(){
-               logger.info("Logged out");
-               fs.unlink(autologinLocation,function(){
+       // Saves locally the settings comming from the frontend
+       s.on("saveSettings", function (settings) {
+               if (settings.userDefined.downloadLocation == defaultDownloadFolder) {
+                       settings.userDefined.downloadLocation = ""
+               } else {
+                       settings.userDefined.downloadLocation = path.resolve(settings.userDefined.downloadLocation + path.sep) + path.sep
+                       mainFolder = settings.userDefined.downloadLocation
+               }
+
+               if (settings.userDefined.queueConcurrency < 1) settings.userDefined.queueConcurrency = 1
+
+               if (settings.userDefined.queueConcurrency != s.trackQueue.concurrency){
+                       s.trackQueue.concurrency = settings.userDefined.queueConcurrency
+               }
+
+               if (settings.userDefined.chartsCountry != configFile.userDefined.chartsCountry){
+                       s.emit("setChartsCountry", {selected: settings.userDefined.chartsCountry})
+                       getChartsTrackListByCountry(settings.userDefined.chartsCountry)
+               }
+
+               if (settings.userDefined.spotifyUser != configFile.userDefined.spotifyUser){
+                       getMyPlaylistList(settings.userDefined.spotifyUser)
+               }
+
+               configFile.userDefined = settings.userDefined;
+               fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
+                       if (err) return
+                       logger.info("Settings updated")
+                       initFolders()
                });
-               return;
        });
 
-       Deezer.onDownloadProgress = function (track, progress) {
-               if (!track.trackSocket) {
-                       return;
+       /*
+        * Downloading section of the app
+       */
+
+       // Gets data from the frontend and creates the track object
+       async function downloadTrack(data){
+               logger.info(`Added to Queue ${data.id}`)
+               try{
+                       var track = await s.Deezer.getTrack(data.id)
+                       data.settings.filename = data.settings.trackNameTemplate
+                       data.settings.foldername = data.settings.albumNameTemplate
+                       let _track = {
+                               name: track.title,
+                               artist: track.artist.name,
+                               size: 1,
+                               downloaded: 0,
+                               failed: 0,
+                               queueId: `id${Math.random().toString(36).substring(2)}`,
+                               id: `${track.id}:${data.settings.maxBitrate}`,
+                               type: 'track',
+                               settings: data.settings || {},
+                               obj: track,
+                       }
+                       addToQueue(_track)
+               }catch(err){
+                       logger.error(`downloadTrack failed: ${err.stack ? err.stack : err}`)
+                       return
                }
-               if(track.trackSocket.currentItem && track.trackSocket.currentItem.type == "track"){
-                       let complete;
-                       if (!track.trackSocket.currentItem.percentage) {
-                               track.trackSocket.currentItem.percentage = 0;
+       }
+       s.on("downloadtrack", async data=>{await downloadTrack(data)})
+
+       // Gets data from the frontend and creates the album object
+       async function downloadAlbum(data){
+               logger.info(`Added to Queue ${data.id}`)
+               try{
+                       var album = await s.Deezer.legacyGetAlbum(data.id)
+                       if (data.settings.tags.discTotal || data.settings.createCDFolder){
+                               var discTotal = await s.Deezer.getAlbum(data.id)
+                               album.discTotal = discTotal.discTotal
                        }
-                       if(track.format == 9){
-                               complete = track.FILESIZE_FLAC;
+                       if (album.nb_tracks == 1){
+                               var track = await s.Deezer.getTrack(album.tracks.data[0].id)
+                               data.settings.filename = data.settings.trackNameTemplate
+                               data.settings.foldername = data.settings.albumNameTemplate
+                               let _track = {
+                                       name: track.title,
+                                       artist: track.artist.name,
+                                       size: 1,
+                                       downloaded: 0,
+                                       failed: 0,
+                                       queueId: `id${Math.random().toString(36).substring(2)}`,
+                                       id: `${track.id}:${data.settings.maxBitrate}`,
+                                       type: 'track',
+                                       settings: data.settings || {},
+                                       obj: track,
+                               }
+                               addToQueue(_track)
                        }else{
-                               if (track.FILESIZE_MP3_320) {
-                                       complete = track.FILESIZE_MP3_320;
-                               } else if (track.FILESIZE_MP3_256) {
-                                       complete = track.FILESIZE_MP3_256;
-                               } else {
-                                       complete = track.FILESIZE_MP3_128 || 0;
+                               album.tracks = await s.Deezer.getAlbumTracks(data.id)
+                               data.settings.filename = data.settings.albumTrackNameTemplate
+                               data.settings.foldername = data.settings.albumNameTemplate
+                               let _album = {
+                                       name: album.title,
+                                       artist: album.artist.name,
+                                       size: album.tracks.length,
+                                       downloaded: 0,
+                                       failed: 0,
+                                       queueId: `id${Math.random().toString(36).substring(2)}`,
+                                       id: `${album.id}:${data.settings.maxBitrate}`,
+                                       type: 'album',
+                                       settings: data.settings || {},
+                                       obj: album,
                                }
+                               addToQueue(_album)
                        }
-                       let percentage = (progress / complete) * 100;
-                       if ((percentage - track.trackSocket.currentItem.percentage > 1) || (progress == complete)) {
-                               track.trackSocket.currentItem.percentage = percentage;
-                               track.trackSocket.emit("downloadProgress", {
-                                       queueId: track.trackSocket.currentItem.queueId,
-                                       percentage: track.trackSocket.currentItem.percentage
-                               });
-                       }
+                       return
+               }catch(err){
+                       logger.error(`downloadAlbum failed: ${err.stack ? err.stack : err}`)
+                       return
                }
-       };
-
-       function addToQueue(object) {
-               socket.downloadQueue[object.queueId] = object;
-               socket.emit('addToQueue', object);
-               queueDownload(getNextDownload());
        }
+       s.on("downloadalbum", async data=>{await downloadAlbum(data)});
 
-       function getNextDownload() {
-               if (socket.currentItem != null || Object.keys(socket.downloadQueue).length == 0) {
-                       if (Object.keys(socket.downloadQueue).length == 0 && socket.currentItem == null) {
-                               socket.emit("emptyDownloadQueue", {});
-                       }
-                       return null;
+       // Gets data from the frontend and creates for each album an album object
+       async function downloadArtist(data){
+               logger.info(`Added to Queue ${data.id}`)
+               try{
+                       var albums = await s.Deezer.legacyGetArtistAlbums(data.id);
+                       (function sendAllAlbums(i) {
+                               setTimeout(function () {
+                                       data.id = albums.data[albums.data.length-1-i].id
+                                       downloadAlbum(JSON.parse(JSON.stringify(data)))
+                                       if (--i+1) sendAllAlbums(i)
+                               }, 100)
+                       })(albums.data.length-1)
+               }catch(err){
+                       logger.error(`downloadArtist failed: ${err.stack ? err.stack : err}`)
+                       return
                }
-               socket.currentItem = socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-               return socket.currentItem;
        }
-
-       function socketDownloadTrack(data){
-               Deezer.getTrack(data.id, data.settings.hifi, function (track, err) {
-                       if (err) {
-                               return;
-                       }
-                       let queueId = "id" + Math.random().toString(36).substring(2);
-                       let _track = {
-                               name: track["SNG_TITLE"],
-                               artist: track["ART_NAME"],
-                               size: 1,
+       s.on("downloadartist", async data=>{ await downloadArtist(data)});
+
+       // Gets data from the frontend and creates the playlist object
+       async function downloadPlaylist(data){
+               logger.info(`Added to Queue ${data.id}`)
+               try{
+                       var playlist = await s.Deezer.legacyGetPlaylist(data.id)
+                       data.settings.filename = data.settings.playlistTrackNameTemplate
+                       data.settings.foldername = data.settings.albumNameTemplate
+                       playlist.tracks = await s.Deezer.getPlaylistTracks(data.id)
+                       let _playlist = {
+                               name: playlist.title,
+                               artist: playlist.creator.name,
+                               size: playlist.tracks.length,
                                downloaded: 0,
                                failed: 0,
-                               queueId: queueId,
-                               id: track["SNG_ID"],
-                               type: "track"
-                       };
-                       data.settings.trackInfo= slimDownTrackInfo(track);
-                       if (track["VERSION"]) _track.name = _track.name + " " + track["VERSION"];
-                       _track.settings = data.settings || {};
-                       addToQueue(_track);
-               });
-       }
-       socket.on("downloadtrack", data=>{socketDownloadTrack(data)});
-
-       function socketDownloadPlaylist(data){
-               Deezer.getPlaylist(data.id, function (playlist, err) {
-                       if (err) {
-                               return;
+                               queueId: `id${Math.random().toString(36).substring(2)}`,
+                               id: `${playlist.id}:${data.settings.maxBitrate}`,
+                               type: "playlist",
+                               settings: data.settings || {},
+                               obj: playlist,
                        }
-                       let queueId = "id" + Math.random().toString(36).substring(2);
+                       addToQueue(_playlist)
+               }catch(err){
+                       logger.error(`downloadPlaylist failed: ${err.stack ? err.stack : err}`)
+                       return
+               }
+       }
+       s.on("downloadplaylist", data=>{downloadPlaylist(data)});
+
+       // Gets data from the frontend and creates the object fot the artist top tracks
+       async function downloadArtistTop(data){
+               logger.info(`Added to Queue ${data.id}`)
+               try{
+                       var artist = await s.Deezer.legacyGetArtist(data.id)
+                       data.settings.filename = data.settings.playlistTrackNameTemplate
+                       data.settings.foldername = data.settings.albumNameTemplate
+                       artist.tracks = await s.Deezer.getArtistTopTracks(data.id)
                        let _playlist = {
-                               name: playlist["title"],
-                               size: playlist.nb_tracks,
+                               name: artist.name + " Most played tracks",
+                               artist: artist.name,
+                               size: artist.tracks.length,
                                downloaded: 0,
-                               artist: playlist.creator.name,
                                failed: 0,
-                               queueId: queueId,
-                               id: playlist["id"],
+                               queueId: `id${Math.random().toString(36).substring(2)}`,
+                               id: `${artist.id}:${data.settings.maxBitrate}`,
                                type: "playlist",
-                               cover: playlist["picture_small"],
-                               tracks: playlist.tracks.data
-                       };
-                       _playlist.settings = data.settings || {};
-                       if (_playlist.size>400){
-                               Deezer.getPlaylistTracks(data.id, function (playlist, err) {
-                                       _playlist.size = playlist.data.length
-                                       _playlist.tracks = playlist.data
-                                       addToQueue(_playlist);
-                               })
-                       }else{
-                               addToQueue(_playlist);
+                               settings: data.settings || {},
+                               obj: artist,
                        }
-               });
+                       addToQueue(_playlist)
+               }catch(err){
+                       logger.error(`downloadArtistTop failed: ${err.stack ? err.stack : err}`)
+                       return
+               }
        }
-       socket.on("downloadplaylist", data=>{socketDownloadPlaylist(data)});
+       s.on("downloadartisttop", data=>{downloadArtistTop(data)});
 
-       function socketDownloadAlbum(data){
-               Deezer.getAlbum(data.id, function (album, err) {
-                       if (err) {
-                               return;
+       // Gets data from the frontend and creates the spotify playlist object
+       async function downloadSpotifyPlaylist(data){
+               logger.info(`Added to Queue ${data.id}`)
+               if (spotifySupport){
+                       try{
+                               let creds = await Spotify.clientCredentialsGrant()
+                               Spotify.setAccessToken(creds.body['access_token'])
+                               var offset = 0
+                               data.settings.filename = data.settings.playlistTrackNameTemplate
+                               data.settings.foldername = data.settings.albumNameTemplate
+                               var resp = await Spotify.getPlaylist(data.id, {fields: "id,name,owner,images,tracks(total)"})
+                               var _playlist = {
+                                       name: resp.body.name,
+                                       artist: (resp.body.owner.display_name ? resp.body.owner.display_name : resp.body.owner.id),
+                                       size: resp.body.tracks.total,
+                                       downloaded: 0,
+                                       failed: 0,
+                                       queueId: `id${Math.random().toString(36).substring(2)}`,
+                                       settings: data.settings || {},
+                                       id: `${resp.body.id}:${data.settings.maxBitrate}`,
+                                       type: "spotifyplaylist",
+                                       obj: resp.body
+                               }
+                               var numPages=Math.floor((_playlist.size-1)/100)
+                               var trackList = new Array(_playlist.size)
+                               do{
+                                       var resp = await Spotify.getPlaylistTracks(data.id, {fields: "items(track(artists,name,album,external_ids))", offset: offset*100})
+                                       resp.body.items.forEach((track, i) => {
+                                               trackList[i+(offset*100)] = track.track
+                                       })
+                                       offset++
+                               }while(offset<=numPages)
+                               _playlist.obj.tracks = trackList
+                               addToQueue(_playlist)
+                       }catch(err){
+                               logger.error(`downloadSpotifyPlaylist failed: ${err.stack ? err.stack : err}`)
+                               return
                        }
-                       let queueId = "id" + Math.random().toString(36).substring(2);
-                       let _album = {
-                               name: album["title"],
-                               label: album["label"],
-                               artist: album["artist"].name,
-                               size: album.tracks.data.length,
-                               downloaded: 0,
-                               failed: 0,
-                               queueId: queueId,
-                               id: album["id"],
-                               type: "album",
-                               tracks: album.tracks.data
-                       };
-                       data.settings.albumInfo = slimDownAlbumInfo(album)
-                       _album.settings = data.settings || {};
-                       addToQueue(_album);
-               });
+               }else{
+                       s.emit("message", {title: "Spotify Support is not enabled", msg: "You should add authCredentials.js in your config files to use this feature<br>You can see how to do that in <a href=\"https://notabug.org/RemixDevs/DeezloaderRemix/wiki/Spotify+Features\">this guide</a>"})
+               }
        }
-       socket.on("downloadalbum", data=>{socketDownloadAlbum(data)});
-
-       function socketDownloadArtist(data){
-               Deezer.getArtistAlbums(data.id, function (albums, err) {
-                       if (err) {
-                               return;
+       s.on("downloadspotifyplaylist", data=>{downloadSpotifyPlaylist(data)})
+
+       // Converts the spotify track to a deezer one
+       // It tries first with the isrc (best way of conversion)
+       // Fallbacks to the old way, using search
+       async function convertSpotify2Deezer(track){
+               if (!track) return 0
+               try{
+                       if (track.external_ids.isrc){
+                               let resp = await s.Deezer.legacyGetTrackByISRC(track.external_ids.isrc)
+                               return resp.id
                        }
-                       (function sendAllAlbums(i) {
-                               setTimeout(function () {
-                     data.id = albums.data[albums.data.length-1-i].id;
-                                       socketDownloadAlbum(data);
-                     if (--i+1) sendAllAlbums(i);
-                       }, 100)
-                       })(albums.data.length-1);
-               });
+               }catch(err){
+                       logger.warn("ISRC not found, falling back to old method")
+               }
+               let resp
+               track.artists[0].name = track.artists[0].name.replace(/–/g,"-").replace(/’/g, "'")
+               track.name = track.name.replace(/–/g,"-").replace(/’/g, "'")
+               track.album.name = track.album.name.replace(/–/g,"-").replace(/’/g, "'")
+               try{
+                       resp = await s.Deezer.legacySearch(`artist:"${track.artists[0].name}" track:"${track.name}" album:"${track.album.name}"`, "track", 1)
+               }catch(err){logger.err(`Convert2Spotify: ${err.stack ? err.stack : err}`)}
+               if (resp.data[0]) return resp.data[0].id
+               try{
+                       resp = await s.Deezer.legacySearch(`artist:"${track.artists[0].name}" track:"${track.name}"`, "track", 1)
+               }catch(err){logger.err(`Convert2Spotify: ${err.stack ? err.stack : err}`)}
+               if (resp.data[0]) return resp.data[0].id
+               if (track.name.indexOf("(") < track.name.indexOf(")")){
+                       try{
+                               resp = await s.Deezer.legacySearch(`artist:"${track.artists[0].name}" track:"${track.name.split("(")[0]}"`, "track", 1)
+                       }catch(err){logger.err(`Convert2Spotify: ${err.stack ? err.stack : err}`)}
+                       if (resp.data[0]) return resp.data[0].id
+               }else if (track.name.indexOf(" - ")>0){
+                       try{
+                               resp = await s.Deezer.legacySearch(`artist:"${track.artists[0].name}" track:"${track.name.split(" - ")[0]}"`, "track", 1)
+                       }catch(err){logger.err(`Convert2Spotify: ${err.stack ? err.stack : err}`)}
+                       if (resp.data[0]) return resp.data[0].id
+               }else{
+                       return 0
+               }
+               return 0
        }
-       socket.on("downloadartist", data=>{socketDownloadArtist(data)});
 
+       // All the above functions call this function
+       // It adds the object to an array and adds the promise for the download to the object itself
+       function addToQueue(object) {
+               s.downloadQueue[object.queueId] = object
+               s.emit('addToQueue', object)
+               s.downloadQueue[object.queueId].downloadQueuePromise = s.dqueue.push(addNextDownload, { args: object })
+       }
 
-       socket.on("downloadspotifyplaylist", function (data) {
-               spotifyApi.clientCredentialsGrant().then(function(creds) {
-                       spotifyApi.setAccessToken(creds.body['access_token']);
-                       return spotifyApi.getPlaylist(data.settings.currentSpotifyUser, data.id, {fields: "id,name,owner,images,tracks(total,items(track.artists,track.name))"})
-               }).then(function(resp) {
-                       let queueId = "id" + Math.random().toString(36).substring(2);
-                       let _playlist = {
-                               name: resp.body["name"],
-                               artist: (resp.body["owner"]["display_name"] ? resp.body["owner"]["display_name"] : resp.body["owner"]["id"]),
-                               size: resp.body["tracks"]["total"],
-                               downloaded: 0,
-                               failed: 0,
-                               queueId: queueId,
-                               id: resp.body["id"],
-                               type: "spotifyplaylist",
-                               cover: (resp.body["images"] ? resp.body["images"][0]["url"] : null),
-                               tracks: resp.body["tracks"]["items"]
-                       };
-                       _playlist.settings = data.settings || {};
-                       addToQueue(_playlist);
+       // Wrapper for queue download
+       function addNextDownload(obj, token){
+               return new Promise(async (resolve, reject) => {
+      await queueDownload(obj)
+                       resolve()
+    }).then(() => new Promise((resolve, reject) => {
+      if (token.cancelled)
+        reject()
+      else
+        resolve()
+    }))
+       }
+
+       // Cancels download
+       // TODO: Might check this one, could be a little buggy
+       function cancelDownload(queueId, cleanAll=false){
+               if (!queueId) return
+               let cancel = false
+               let cancelSuccess
+               if (s.downloadQueue[queueId]){
+                       cancel = true;
+                       if (s.downloadQueue[queueId].downloadQueuePromise) s.downloadQueue[queueId].downloadQueuePromise.cancel()
+                       if (s.downloadQueue[Object.keys(s.downloadQueue)[0]].queueId == queueId) {
+                               s.trackQueue = queue({
+                                       autostart: true,
+                                       concurrency: s.trackQueue.concurrency
+                               })
+                       }
+                       delete s.downloadQueue[queueId]
+               }
+
+               if (cancel) {
+                       s.emit("cancelDownload", {queueId: queueId, cleanAll: cleanAll});
+               }
+       }
+       s.on("cancelDownload", function (data) {cancelDownload(data.queueId)});
+
+       s.on("cancelAllDownloads", function(data){
+               data.queueList.forEach(x=>{
+                       cancelDownload(x, true);
                })
-       });
+               s.emit("cancelAllDownloads")
+       })
+
+       /*function getNextDownload() {
+               if (s.currentItem != null || Object.keys(s.downloadQueue).length == 0) {
+                       if (Object.keys(s.downloadQueue).length == 0 && s.currentItem == null) {
+                               s.emit("emptyDownloadQueue", {})
+                       }
+                       return null
+               }
+               s.currentItem = s.downloadQueue[Object.keys(s.downloadQueue)[0]]
+               return s.currentItem
+       }*/
 
-       //currentItem: the current item being downloaded at that moment such as a track or an album
        //downloadQueue: the tracks in the queue to be downloaded
-       //lastQueueId: the most recent queueId
        //queueId: random number generated when user clicks download on something
-       function queueDownload(downloading) {
-               if (!downloading) return;
+       async function queueDownload(downloading) {
+               if (!downloading) return
 
-               // New batch emits new message
-               if (socket.lastQueueId != downloading.queueId) {
-                       if (downloading.type != "spotifyplaylist"){
-                               socket.emit("downloadStarted", {queueId: downloading.queueId});
-                       }
-                       socket.lastQueueId = downloading.queueId;
+               if (downloading.type != "spotifyplaylist"){
+                       s.emit("downloadStarted", {queueId: downloading.queueId})
                }
 
+               downloading.errorLog = "";
+               downloading.searchedLog = "";
+
+               let filePath;
                logger.info(`Registered ${downloading.type}: ${downloading.id} | ${downloading.artist} - ${downloading.name}`);
                switch(downloading.type){
+                       /*
+                       *  TRACK DOWNLOAD
+                       */
                        case "track":
-                               let alternativeID = 0;
-                               if (downloading.settings.trackInfo.FALLBACK)
-                                       if (downloading.settings.trackInfo.FALLBACK.SNG_ID)
-                                               alternativeID = downloading.settings.trackInfo.FALLBACK.SNG_ID;
-                               downloadTrack({id: downloading.id, fallback: (alternativeID == 0 ? null : alternativeID), name: downloading.name, artist: downloading.artist, queueId: downloading.queueId}, downloading.settings, null, function (err, track) {
-                                       if (err) {
-                                               downloading.failed++;
-                                       } else {
-                                               downloading.downloaded++;
+                               var downloadPromise = new Promise(async (resolve,reject)=>{
+                                       try{
+                                               await downloadTrackObject(downloading.obj, downloading.queueId, downloading.settings)
+                                               downloading.downloaded++
+                                       }catch(err){
+                                               downloading.failed++
                                        }
-                                       downloading.settings = null;
-                                       socket.emit("updateQueue", downloading);
-                                       socket.emit("downloadProgress", {
+                                       s.emit("updateQueue", {
+                                               name: downloading.name,
+                                               artist: downloading.artist,
+                                               size: downloading.size,
+                                               downloaded: downloading.downloaded,
+                                               failed: downloading.failed,
+                                               queueId: downloading.queueId,
+                                               id: downloading.id,
+                                               type: downloading.type,
+                                       })
+                                       s.emit("downloadProgress", {
                                                queueId: downloading.queueId,
                                                percentage: 100
-                                       });
-                                       if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                       socket.currentItem = null;
-                                       queueDownload(getNextDownload());
-                               });
-                               break;
-                       case "album":
-                               downloading.playlistContent = downloading.tracks.map((t) => {
-                                       if (t.FALLBACK){
-                                               if (t.FALLBACK.SNG_ID)
-                                                       return {id: t.id, fallback: t.FALLBACK.SNG_ID, name: t.title, artist: t.artist.name, queueId: downloading.queueId}
-                                       }else{
-                                               return {id: t.id, name: t.title, artist: t.artist.name, queueId: downloading.queueId}
-                                       }
+                                       })
+                                       resolve()
                                })
+                               try{
+                                       await downloadPromise
+                               }catch(err){
+                                       if (err) logger.error(`queueDownload:track failed: ${err.stack ? err.stack : err}`)
+                                       logger.info("Downloading Stopped")
+                               }
+                       break
+                       /*
+                       *  ALBUM DOWNLOAD
+                       */
+                       case "album":
                                downloading.settings.albName = downloading.name;
                                downloading.settings.artName = downloading.artist;
-                               downloading.errorLog = "";
-                               downloading.settings.playlistArr = Array(downloading.size);
-                               downloading.finished = new Promise((resolve,reject)=>{
-                                       downloading.playlistContent.every(function (t) {
-                                               socket.trackQueue.push(cb=>{
-                                                       if (!socket.downloadQueue[downloading.queueId]) {
-                                                               reject();
-                                                               return false;
+                               downloading.playlistArr = Array(downloading.size);
+                               filePath = mainFolder;
+                               if (downloading.settings.createArtistFolder || downloading.settings.createAlbumFolder) {
+                                       if (downloading.settings.createArtistFolder) {
+                                               filePath += antiDot(fixName(downloading.settings.artName)) + path.sep;
+                                       }
+                                       if (downloading.settings.createAlbumFolder) {
+                                               filePath += antiDot(settingsRegexAlbum(downloading.settings.foldername,downloading.settings.artName,downloading.settings.albName,downloading.obj.release_date.slice(0, 4),downloading.obj.record_type,downloading.obj.explicit_lyrics,downloading.obj.label, downloading.obj.genres)) + path.sep;
+                                       }
+                               } else if (downloading.settings.artName) {
+                                       filePath += antiDot(settingsRegexAlbum(downloading.settings.foldername,downloading.settings.artName,downloading.settings.albName,downloading.obj.release_date.slice(0, 4),downloading.obj.record_type,downloading.obj.explicit_lyrics,downloading.obj.label, downloading.obj.genres)) + path.sep;
+                               }
+                               let ajson = {
+                                       artist : downloading.obj.artist,
+                                       nb_tracks : downloading.obj.nb_tracks,
+                                       upc : downloading.obj.upc,
+                                       record_type : downloading.obj.record_type,
+                                       explicit_lyrics : downloading.obj.explicit_lyrics,
+                                       label : downloading.obj.label,
+                                       release_date : downloading.obj.release_date,
+                                       genres : downloading.obj.genres,
+                                       discTotal: downloading.obj.discTotal ? downloading.obj.discTotal : null
+                               }
+                               downloading.downloadPromise = new Promise((resolve,reject)=>{
+                                       downloading.obj.tracks.every(function (t) {
+                                               s.trackQueue.push(async cb=>{
+                                                       if (!s.downloadQueue[downloading.queueId]) {
+                                                               reject()
+                                                               return false
                                                        }
-                                                       logger.info(`Now downloading: ${t.artist} - ${t.name}`)
-                                                       downloadTrack(t, downloading.settings, null, function (err, track) {
-                                                               if (!err) {
-                                                                       downloading.downloaded++;
-                                                                       downloading.settings.playlistArr[track[0]] = track[1];
-                                                               } else {
-                                                                       downloading.failed++;
-                                                                       downloading.errorLog += track+"\r\n";
-                                                               }
-                                                               socket.emit("downloadProgress", {
-                                                                       queueId: downloading.queueId,
-                                                                       percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
-                                                               });
-                                                               socket.emit("updateQueue", downloading);
-                                                               if (downloading.downloaded + downloading.failed == downloading.size)
-                                                                       resolve();
-                                                               cb();
+                                                       t.ajson = ajson
+                                                       logger.info(`Now downloading: ${t.artist.name} - ${t.title}`)
+                                                       try{
+                                                               await downloadTrackObject(t, downloading.queueId, downloading.settings)
+                                                               downloading.downloaded++
+                                                               downloading.playlistArr[t.playlistData[0]] = t.playlistData[1].split(filePath)[1]
+                                                               if (t.searched) downloading.searchedLog += `${t.artist.name} - ${t.name}\r\n`
+                                                       }catch(err){
+                                                               downloading.failed++
+                                                               downloading.errorLog += `${t.id} | ${t.artist.name} - ${t.title} | ${err}\r\n`
+                                                       }
+                                                       s.emit("downloadProgress", {
+                                                               queueId: downloading.queueId,
+                                                               percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
                                                        });
-                                               });
-                                               return true;
-                                       });
+                                                       s.emit("updateQueue", {
+                                                               name: downloading.name,
+                                                               artist: downloading.artist,
+                                                               size: downloading.size,
+                                                               downloaded: downloading.downloaded,
+                                                               failed: downloading.failed,
+                                                               queueId: downloading.queueId,
+                                                               id: downloading.id,
+                                                               type: downloading.type,
+                                                       })
+                                                       if (downloading.downloaded + downloading.failed >= downloading.size) resolve()
+                                                       cb()
+                                               })
+                                               return true
+                                       })
                                })
-                               downloading.finished.then(()=>{
-                                       if (downloading.countPerAlbum) {
-                                               if (Object.keys(socket.downloadQueue).length > 1 && Object.keys(socket.downloadQueue)[1] == downloading.queueId) {
-                                                       socket.downloadQueue[downloading.queueId].download = downloading.downloaded;
-                                               }
-                                               socket.emit("updateQueue", downloading);
-                                       }
-                                       logger.info("Album finished "+downloading.name);
-                                       socket.emit("downloadProgress", {
+                               try{
+                                       await downloading.downloadPromise
+                                       logger.info("Album finished downloading: "+downloading.name);
+                                       s.emit("downloadProgress", {
                                                queueId: downloading.queueId,
                                                percentage: 100
                                        });
-                                       let filePath = mainFolder;
-                                       if (downloading.settings.createArtistFolder || downloading.settings.createAlbumFolder) {
-                                               if (downloading.settings.createArtistFolder) {
-                                                       filePath += antiDot(fixName(downloading.settings.artName)) + path.sep;
-                                               }
-                                               if (downloading.settings.createAlbumFolder) {
-                                                       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;
-                                               }
-                                       } else if (downloading.settings.artName) {
-                                               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;
-                                       }
                                        if (downloading.settings.logErrors){
                                                if (downloading.errorLog != ""){
                                                        if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
@@ -452,71 +830,76 @@ io.sockets.on('connection', function (socket) {
                                                        if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
                                                }
                                        }
+                                       if (downloading.settings.logSearched){
+                                               if (downloading.searchedLog != ""){
+                                                       if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
+                                                       fs.writeFileSync(filePath+"alternativeSongs.txt",downloading.searchedLog)
+                                               }else{
+                                                       if (fs.existsSync(filePath+"alternativeSongs.txt")) fs.unlinkSync(filePath+"alternativeSongs.txt");
+                                               }
+                                       }
                                        if (downloading.settings.createM3UFile){
-                                               fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
+                                               fs.writeFileSync(filePath+"playlist.m3u", downloading.playlistArr.join("\r\n"));
                                        }
-                                       if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                       socket.currentItem = null;
-                                       queueDownload(getNextDownload());
-                               }).catch((err)=>{
-                                       if (err) return logger.error(err.stack);
+                               }catch(err){
+                                       if (err) logger.error(`queueDownload:album failed: ${err.stack ? err.stack : err}`)
                                        logger.info("Stopping the album queue");
-                                       if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                       socket.currentItem = null;
-                                       queueDownload(getNextDownload());
-                               });
-                               break;
+                               }
+                       break
+                       /*
+                       *  PLAYLIST DOWNLOAD
+                       */
                        case "playlist":
-                               downloading.playlistContent = downloading.tracks.map((t,i) => {
-                                       if (t.FALLBACK){
-                                               if (t.FALLBACK.SNG_ID)
-                                                       return {id: t.id, fallback: t.FALLBACK.SNG_ID, name: t.title, artist: t.artist.name, index: i, queueId: downloading.queueId}
-                                       }else{
-                                               return {id: t.id, name: t.title, artist: t.artist.name, index: i, queueId: downloading.queueId}
-                                       }
-                               })
                                downloading.settings.plName = downloading.name;
-                               downloading.errorLog = ""
-                               downloading.settings.playlistArr = Array(downloading.size);
+                               downloading.playlistArr = Array(downloading.size);
                                downloading.settings.playlist = {
-                                       fullSize: downloading.playlistContent.length
+                                       fullSize: downloading.obj.tracks.length
                                };
-                               downloading.finished = new Promise((resolve,reject)=>{
-                                       downloading.playlistContent.every(function (t) {
-                                               socket.trackQueue.push(cb=>{
-                                                       if (!socket.downloadQueue[downloading.queueId]) {
-                                                               reject();
-                                                               return false;
+                               filePath = mainFolder+antiDot(fixName(downloading.settings.plName)) + path.sep
+                               downloading.downloadPromise = new Promise((resolve,reject)=>{
+                                       downloading.obj.tracks.every(function (t, index) {
+                                               s.trackQueue.push(async cb=>{
+                                                       if (!s.downloadQueue[downloading.queueId]) {
+                                                               reject()
+                                                               return false
                                                        }
-                                                       logger.info(`Now downloading: ${t.artist} - ${t.name}`)
-                                                       downloadTrack(t, downloading.settings, null, function (err, track) {
-                                                               if (!err) {
-                                                                       downloading.downloaded++;
-                                                                       downloading.settings.playlistArr[track[0]] = track[1];
-                                                               } else {
-                                                                       downloading.failed++;
-                                                                       downloading.errorLog += track+"\r\n"
-                                                               }
-                                                               socket.emit("downloadProgress", {
-                                                                       queueId: downloading.queueId,
-                                                                       percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
-                                                               });
-                                                               socket.emit("updateQueue", downloading);
-                                                               if (downloading.downloaded + downloading.failed == downloading.size)
-                                                                       resolve();
-                                                               cb();
+                                                       try{
+                                                               await downloadTrackObject(t, downloading.queueId, downloading.settings)
+                                                               downloading.downloaded++
+                                                               downloading.playlistArr[t.playlistData[0]] = t.playlistData[1].split(filePath)[1]
+                                                               if (t.searched) downloading.searchedLog += `${t.artist.name} - ${t.name}\r\n`
+                                                       }catch(err){
+                                                               logger.debug(err.stack ? err.stack : err)
+                                                               downloading.failed++
+                                                               downloading.errorLog += `${t.id} | ${t.artist.name} - ${t.title} | ${err}\r\n`
+                                                       }
+                                                       s.emit("downloadProgress", {
+                                                               queueId: downloading.queueId,
+                                                               percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
                                                        });
-                                               });
-                                               return true;
+                                                       s.emit("updateQueue", {
+                                                               name: downloading.name,
+                                                               artist: downloading.artist,
+                                                               size: downloading.size,
+                                                               downloaded: downloading.downloaded,
+                                                               failed: downloading.failed,
+                                                               queueId: downloading.queueId,
+                                                               id: downloading.id,
+                                                               type: downloading.type,
+                                                       })
+                                                       if (downloading.downloaded + downloading.failed >= downloading.size) resolve()
+                                                       cb()
+                                               })
+                                               return true
                                        })
-                               });
-                               downloading.finished.then(()=>{
+                               })
+                               try{
+                                       await downloading.downloadPromise
                                        logger.info("Playlist finished "+downloading.name);
-                                       socket.emit("downloadProgress", {
+                                       s.emit("downloadProgress", {
                                                queueId: downloading.queueId,
                                                percentage: 100
                                        });
-                                       let filePath = mainFolder+antiDot(fixName(downloading.settings.plName)) + path.sep
                                        if (downloading.settings.logErrors){
                                                if (downloading.errorLog != ""){
                                                        if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
@@ -525,15 +908,23 @@ io.sockets.on('connection', function (socket) {
                                                        if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
                                                }
                                        }
+                                       if (downloading.settings.logSearched){
+                                               if (downloading.searchedLog != ""){
+                                                       if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
+                                                       fs.writeFileSync(filePath+"alternativeSongs.txt",downloading.searchedLog)
+                                               }else{
+                                                       if (fs.existsSync(filePath+"alternativeSongs.txt")) fs.unlinkSync(filePath+"alternativeSongs.txt");
+                                               }
+                                       }
                                        if (downloading.settings.createM3UFile){
-                                               fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
+                                               fs.writeFileSync(filePath + "playlist.m3u", downloading.playlistArr.join("\r\n"));
                                        }
                                        if (downloading.settings.saveArtwork){
                                                if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
-                                               let imgPath = filePath + "folder.jpg";
+                                               let imgPath = filePath + antiDot(settingsRegexCover(downloading.settings.coverImageTemplate,downloading.artist,downloading.name))+(downloading.settings.PNGcovers ? ".png" : ".jpg");
                                                if (downloading.cover){
-                                                       downloading.cover = downloading.cover.replace("56x56",downloading.settings.artworkSize.split(".")[0].substr(1))
-                                                       request.get(downloading.cover, {encoding: 'binary'}, function(error,response,body){
+                                                       downloading.cover = downloading.cover.replace("56x56",`${downloading.settings.artworkSize}x${downloading.settings.artworkSize}`)
+                                                       request.get(downloading.cover, {strictSSL: false,encoding: 'binary'}, function(error,response,body){
                                                                if(error){
                                                                        logger.error(error.stack);
                                                                        return;
@@ -548,866 +939,826 @@ io.sockets.on('connection', function (socket) {
                                                        });
                                                }
                                        }
-                                       if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                       socket.currentItem = null;
-                                       queueDownload(getNextDownload());
-                               }).catch((err)=>{
-                                       if (err) return logger.error(err.stack);
-                                       logger.info("Stopping the playlist queue");
-                                       if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                       socket.currentItem = null;
-                                       queueDownload(getNextDownload());
-                               });
-                               break;
+                               }catch(err){
+                                       if (err) logger.error(`queueDownload:playlist failed: ${err.stack ? err.stack : err}`)
+                                       logger.info("Stopping the playlist queue")
+                               }
+                       break
+                       /*
+                       *  SPOTIFY PLAYLIST DOWNLOAD
+                       */
                        case "spotifyplaylist":
-                       spotifyApi.clientCredentialsGrant().then(function(creds) {
-                               downloading.settings.plName = downloading.name;
-                               downloading.settings.playlistArr = Array(downloading.size);
-                               spotifyApi.setAccessToken(creds.body['access_token']);
-                               numPages=Math.floor((downloading.size-1)/100);
-                               let pages = []
-                               downloading.playlistContent = new Array(downloading.size);
-                               downloading.tracks.map((t,i)=>{
-                                       downloading.playlistContent[i]=new Promise(function(resolve, reject) {
-                                               Deezer.track2ID(t.track.artists[0].name, t.track.name, function (response,err){
-                                                       resolve(response);
-                                               });
-                                       });
-                               })
-                               if (downloading.size>100){
-                                       for (let offset = 1; offset<=numPages; offset++){
-                                               pages.push(new Promise(function(resolvePage) {
-                                                       spotifyApi.getPlaylistTracks(downloading.settings.currentSpotifyUser, downloading.id, {fields: "items(track.artists,track.name)", offset: offset*100}).then(function(resp) {
-                                                               resp.body['items'].forEach((t, index) => {
-                                                                       downloading.playlistContent[(offset*100)+index] = new Promise(function(resolve, reject) {
-                                                                               Deezer.track2ID(t.track.artists[0].name, t.track.name, function (response,err){
-                                                                                       resolve(response);
-                                                                               });
-                                                                       });
-                                                               });
-                                                               resolvePage();
-                                                       });
-                                               }));
-                                       }
+                               downloading.settings.plName = downloading.name
+                               downloading.playlistArr = Array(downloading.size)
+                               downloading.playlistContent = new Array(downloading.size)
+                               logger.info("Waiting for all tracks to be converted");
+                               const convert = async () =>{
+                                       await asyncForEach(downloading.obj.tracks, async (t,i)=>{
+                                               try{
+                                                       downloading.playlistContent[i] = await convertSpotify2Deezer(t)
+                                               }catch(err){
+                                                       logger.error(`queueDownload:spotifyplaylist failed during conversion: ${err.stack ? err.stack : err}`)
+                                               }
+                                       })
                                }
-                               logger.info("Waiting for all pages");
-                               Promise.all(pages).then((val)=>{
-                                       logger.info("Waiting for all tracks to be converted");
-                                       return Promise.all(downloading.playlistContent)
-                               }).then((values)=>{
-                                       if (!socket.downloadQueue[downloading.queueId]) {
-                                               logger.info("Stopping the playlist queue");
-                                               if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                               socket.currentItem = null;
-                                               queueDownload(getNextDownload());
-                                               return;
-                                       }
-                                       logger.info("All tracks converted, starting download");
-                                       socket.emit("downloadStarted", {queueId: downloading.queueId});
-                                       downloading.errorLog = "";
-                                       downloading.settings.playlist = {
-                                               fullSize: values.length
-                                       };
-                                       downloading.finished = new Promise((resolve,reject)=>{
-                                               values.every(function (t) {
-                                                       t.index = values.indexOf(t)
-                                                       t.queueId = downloading.queueId
-                                                       socket.trackQueue.push(cb=>{
-                                                               if (!socket.downloadQueue[downloading.queueId]) {
-                                                                       reject();
-                                                                       return false;
-                                                               }
-                                                               logger.info(`Now downloading: ${t.artist} - ${t.name}`)
-                                                               downloadTrack(t, downloading.settings, null, function (err, track) {
-                                                                       if (!err) {
-                                                                               downloading.downloaded++;
-                                                                               downloading.settings.playlistArr[track[0]] = track[1];
-                                                                       } else {
-                                                                               downloading.failed++;
-                                                                               downloading.errorLog += track+"\r\n"
-                                                                       }
-                                                                       socket.emit("downloadProgress", {
-                                                                               queueId: downloading.queueId,
-                                                                               percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
-                                                                       });
-                                                                       if (downloading.downloaded + downloading.failed == downloading.size)
-                                                                               resolve();
-                                                                       socket.emit("updateQueue", downloading);
-                                                                       cb();
-                                                               });
+                               await convert()
+                               if (!s.downloadQueue[downloading.queueId]) {
+                                       logger.info("Stopping the playlist queue")
+                                       break
+                               }
+                               downloading.trackList = await s.Deezer.getTracks(downloading.playlistContent)
+                               logger.info("All tracks converted, starting download")
+                               s.emit("downloadStarted", {queueId: downloading.queueId})
+                               downloading.settings.playlist = {
+                                       fullSize: downloading.trackList.length
+                               }
+                               filePath = `${mainFolder}${antiDot(fixName(downloading.settings.plName))}${path.sep}`
+                               downloading.downloadPromise = new Promise((resolve,reject)=>{
+                                       downloading.trackList.every(function (t, index) {
+                                               s.trackQueue.push(async cb=>{
+                                                       if (!s.downloadQueue[downloading.queueId]) {
+                                                               reject()
+                                                               return false
+                                                       }
+                                                       t.position = index
+                                                       if (t.id==0){
+                                                               t.title = downloading.obj.tracks[t.position].name
+                                             t.album = {id: 0, title: downloading.obj.tracks[t.position].album.name}
+                                             t.artist = {id: 0, name: downloading.obj.tracks[t.position].artists[0].name}
+                                                       }
+                                                       try{
+                                                               await downloadTrackObject(t, downloading.queueId, downloading.settings)
+                                                               downloading.downloaded++
+                                                               downloading.playlistArr[t.playlistData[0]] = t.playlistData[1].split(filePath)[1]
+                                                               if (t.searched) downloading.searchedLog += `${t.artist.name} - ${t.name}\r\n`
+                                                       }catch(err){
+                                                               downloading.failed++
+                                                               downloading.errorLog += `${t.id} | ${t.artist.name} - ${t.title} | ${err}\r\n`
+                                                       }
+                                                       s.emit("downloadProgress", {
+                                                               queueId: downloading.queueId,
+                                                               percentage: ((downloading.downloaded+downloading.failed) / downloading.size) * 100
                                                        });
-                                                       return true;
-                                               });
+                                                       s.emit("updateQueue", {
+                                                               name: downloading.name,
+                                                               artist: downloading.artist,
+                                                               size: downloading.size,
+                                                               downloaded: downloading.downloaded,
+                                                               failed: downloading.failed,
+                                                               queueId: downloading.queueId,
+                                                               id: downloading.id,
+                                                               type: downloading.type,
+                                                       })
+                                                       if (downloading.downloaded + downloading.failed >= downloading.size) resolve()
+                                                       cb()
+                                               })
+                                               return true
+                                       })
+                               })
+                               try{
+                                       await downloading.downloadPromise
+                                       logger.info("Playlist finished "+downloading.name);
+                                       s.emit("downloadProgress", {
+                                               queueId: downloading.queueId,
+                                               percentage: 100
                                        });
-                                       downloading.finished.then(()=>{
-                                               logger.info("Playlist finished "+downloading.name);
-                                               socket.emit("downloadProgress", {
-                                                       queueId: downloading.queueId,
-                                                       percentage: 100
-                                               });
-                                               let filePath = mainFolder+antiDot(fixName(downloading.settings.plName)) + path.sep
-                                               if (downloading.settings.logErrors){
-                                                       if (downloading.errorLog != ""){
-                                                               if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
-                                                               fs.writeFileSync(filePath+"notFound.txt",downloading.errorLog)
-                                                       }else{
-                                                               if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
-                                                       }
-                                               }
-                                               if (downloading.settings.createM3UFile){
-                                                       fs.writeFileSync(filePath + "playlist.m3u", downloading.settings.playlistArr.join("\r\n"));
+                                       if (downloading.settings.logErrors){
+                                               if (downloading.errorLog != ""){
+                                                       if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
+                                                       fs.writeFileSync(filePath+"notFound.txt",downloading.errorLog)
+                                               }else{
+                                                       if (fs.existsSync(filePath+"notFound.txt")) fs.unlinkSync(filePath+"notFound.txt");
                                                }
-                                               if (downloading.settings.saveArtwork){
+                                       }
+                                       if (downloading.settings.logSearched){
+                                               if (downloading.searchedLog != ""){
                                                        if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
-                                                       let imgPath = filePath + "folder.jpg";
-                                                       if (downloading.cover){
-                                                               request.get(downloading.cover, {encoding: 'binary'}, function(error,response,body){
-                                                                       if(error){
-                                                                               logger.error(error.stack);
+                                                       fs.writeFileSync(filePath+"alternativeSongs.txt",downloading.searchedLog)
+                                               }else{
+                                                       if (fs.existsSync(filePath+"alternativeSongs.txt")) fs.unlinkSync(filePath+"alternativeSongs.txt");
+                                               }
+                                       }
+                                       if (downloading.settings.createM3UFile){
+                                               fs.writeFileSync(filePath + "playlist.m3u", downloading.playlistArr.join("\r\n"));
+                                       }
+                                       if (downloading.settings.saveArtwork){
+                                               if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
+                                               let imgPath = filePath + antiDot(settingsRegexCover(downloading.settings.coverImageTemplate,downloading.artist,downloading.name))+(downloading.settings.PNGcovers ? ".png" : ".jpg");
+                                               if (downloading.obj.images){
+                                                       downloading.cover = downloading.obj.images[0].url.replace("56x56",`${downloading.settings.artworkSize}x${downloading.settings.artworkSize}`)
+                                                       request.get(downloading.cover, {strictSSL: false,encoding: 'binary'}, function(error,response,body){
+                                                               if(error){
+                                                                       logger.error(error.stack);
+                                                                       return;
+                                                               }
+                                                               fs.outputFile(imgPath,body,'binary',function(err){
+                                                                       if(err){
+                                                                               logger.error(err.stack);
                                                                                return;
                                                                        }
-                                                                       fs.outputFile(imgPath,body,'binary',function(err){
-                                                                               if(err){
-                                                                                       logger.error(err.stack);
-                                                                                       return;
-                                                                               }
-                                                                               logger.info(`Cover downloaded for: ${downloading.settings.plName}`)
-                                                                       })
-                                                               });
-                                                       }
+                                                                       logger.info(`Cover downloaded for: ${downloading.settings.plName}`)
+                                                               })
+                                                       });
                                                }
-                                               if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                               socket.currentItem = null;
-                                               queueDownload(getNextDownload());
-                                       }).catch((err)=>{
-                                               if (err) return logger.error(err.stack);
-                                               logger.info("Stopping the playlist queue");
-                                               if (downloading && socket.downloadQueue[Object.keys(socket.downloadQueue)[0]] && (Object.keys(socket.downloadQueue)[0] == downloading.queueId)) delete socket.downloadQueue[Object.keys(socket.downloadQueue)[0]];
-                                               socket.currentItem = null;
-                                               queueDownload(getNextDownload());
-                                       });
-                               }).catch((err)=>{
-                                       logger.error('Something went wrong!'+err.stack);
-                               });
-                       }).catch((err)=>{
-                               logger.error('Something went wrong!'+err.stack);
-                       });
-                       break;
+                                       }
+                               }catch(err){
+                                       if (err) logger.error(`queueDownload:spotifyplaylist failed: ${err.stack ? err.stack : err}`)
+                                       logger.info("Stopping the playlist queue")
+                               }
+                       break
+               }
+               if (downloading && s.downloadQueue[Object.keys(s.downloadQueue)[0]] && (Object.keys(s.downloadQueue)[0] == downloading.queueId)) delete s.downloadQueue[Object.keys(s.downloadQueue)[0]]
+               if (Object.keys(s.downloadQueue).length == 0) {
+                       s.emit("emptyDownloadQueue", {})
                }
        }
 
-       socket.on("getChartsCountryList", function (data) {
-               Deezer.getChartsTopCountry(function (charts, err) {
-                       if(err){
-                               return;
-                       }
-                       if(charts){
-                               charts = charts.data || [];
-                       }else{
-                               charts = [];
-                       }
-                       let countries = [];
-                       for (let i = 0; i < charts.length; i++) {
-                               let obj = {
-                                       country: charts[i].title.replace("Top ", ""),
-                                       picture_small: charts[i].picture_small,
-                                       picture_medium: charts[i].picture_medium,
-                                       picture_big: charts[i].picture_big
-                               };
-                               countries.push(obj);
-                       }
-                       socket.emit("getChartsCountryList", {countries: countries, selected: data.selected});
-               });
-       });
-
-       socket.on("getChartsTrackListByCountry", function (data) {
-               if (!data.country) {
-                       socket.emit("getChartsTrackListByCountry", {err: "No country passed"});
-                       return;
+       // This function takes the track object and does all the stuff to download it
+       async function downloadTrackObject(track, queueId, settings) {
+               if (!s.downloadQueue[queueId]) {
+                       logger.error(`[${track.artist.name} - ${track.title}] Failed to download: Not in queue`)
+                       throw new Error("Not in queue")
+                       return false
+               }
+               if (parseInt(track.id) == 0){
+                       logger.error(`[${track.artist.name} - ${track.title}] Failed to download: Song not Found`)
+                       throw new Error("Song not Found")
+                       return false
                }
-               Deezer.getChartsTopCountry(function (charts, err) {
-                       if(err) return;
-                       if(charts){
-                               charts = charts.data || [];
-                       }else{
-                               charts = [];
-                       }
-                       let countries = [];
-                       for (let i = 0; i < charts.length; i++) {
-                               countries.push(charts[i].title.replace("Top ", ""));
-                       }
 
-                       if (countries.indexOf(data.country) == -1) {
-                               socket.emit("getChartsTrackListByCountry", {err: "Country not found"});
-                               return;
+               /* Album information is necessary for the following tags:
+                * album_artist
+                * album_artist_picture
+                * trackTotal
+                * recordType
+                * barcode
+                * explicit
+                * label
+                * genres
+                * date
+               */
+               if (parseInt(track.id)>0){
+                       var ajson
+                       if (!track.ajson){
+                               try{
+                                       logger.info(`[${track.artist.name} - ${track.title}] Getting album info`)
+                                       ajson = await s.Deezer.legacyGetAlbum(track.album.id)
+                               }catch(err){
+                                       logger.warn(`[${track.artist.name} - ${track.title}] Album not found, trying to reach deeper`)
+                                       try{
+                                               ajson = await s.Deezer.getAlbum(track.album.id)
+                                               ajson.fromNewAPI = true
+                                       } catch(err){
+                                               if(track.fallbackId){
+                                                       logger.warn(`[${track.artist.name} - ${track.title}] Failed to download track, falling on alternative`)
+                                                       track = await s.Deezer.getTrack(track.fallbackId)
+                                                       return downloadTrackObject(track, queueId, settings)
+                                               }else{
+                                                       logger.error(`[${track.artist.name} - ${track.title}] Failed to download: ${err}`)
+                                                       return
+                                               }
+                                       }
+                               }
+                       }else{
+                               ajson = track.ajson
                        }
-                       let playlistId = charts[countries.indexOf(data.country)].id;
-                       Deezer.getPlaylistTracks(playlistId, function (tracks, err) {
-                               if (err) {
-                                       socket.emit("getChartsTrackListByCountry", {err: err});
-                                       return;
+                       if (!ajson.fromNewAPI){
+                               // Aquiring discTotal (only if necessary)
+                               if ((settings.tags.discTotal || settings.createCDFolder) && parseInt(track.id)>0){
+                                       if (!ajson.discTotal){
+                                               logger.info(`[${track.artist.name} - ${track.title}] Getting total disc number`);
+                                               var discTotal = await s.Deezer.getAlbum(ajson.id)
+                                               track.discTotal = discTotal.discTotal
+                                       }else{
+                                               track.discTotal = ajson.discTotal
+                                       }
                                }
-                               socket.emit("getChartsTrackListByCountry", {
-                                       playlist: charts[countries.indexOf(data.country)],
-                                       tracks: tracks.data
-                               });
-                       });
-               });
-       });
+                               track.album.artist = {
+                                       id: ajson.artist.id,
+                                       name: ajson.artist.name,
+                                       picture: ajson.artist.picture_small.split("/56x56-000000-80-0-0.jpg")[0].split(s.Deezer.artistPicturesHost)[1],
+                               }
+                               track.trackTotal = ajson.nb_tracks
+                               track.album.barcode = ajson.upc
+                               if (!ajson.record_type){
+                                       track.recordType = swichReleaseType(track.recordType)
+                               }else{
+                                       track.recordType = ajson.record_type
+                               }
+                               if (ajson.explicit_lyrics){
+                                       track.album.explicit = ajson.explicit_lyrics;
+                               }
+                               if(ajson.label){
+                                       track.publisher = ajson.label;
+                               }
+                               if (ajson.release_date) {
+                                       track.date = {
+                                               day: ajson.release_date.slice(8,10),
+                                               month: ajson.release_date.slice(5,7),
+                                               year: ajson.release_date.slice(0, 4),
+                                               slicedYear: (settings.dateFormatYear == "2" ? ajson.release_date.slice(2, 4) : ajson.release_date.slice(0, 4))
+                                       }
+                               }else if(!track.date){
+                                       track.date = {
+                                               day: 0,
+                                               month: 0,
+                                               year: 0,
+                                               slicedYear: 0
+                                       }
+                               }
+                               if(ajson.genres && ajson.genres.data[0] && ajson.genres.data[0].name){
+                                       track.genre = [];
+                                       genreArray = [];
+                                       ajson.genres.data.forEach(function(genre){
+                                               genreArray.push(genre.name);
+                                       });
+                                       uniqueArray(genreArray, track.genre, false)
+                               }
+                       }else{
+                               // Missing barcode, genre, recordType
+                               track.album = ajson
+                               track.date = track.album.date
+                               // TODO: Make a loop for each artist
 
-       socket.on("getMePlaylistList", function (d) {
-               logger.info("Loading Personal Playlists")
-               Deezer.getMePlaylists(function (data, err) {
-                       if(err){
-                               return;
                        }
-                       if(data){
-                               data = data.data || [];
+
+                       // Acquiring bpm (only if necessary)
+                       if (settings.tags.bpm){
+                               logger.info(`[${track.artist.name} - ${track.title}] Getting BPM`);
+                               try{
+                                       var bpm = await s.Deezer.legacyGetTrack(track.id)
+                                       track.bpm = bpm.bpm
+                               }catch(err){
+                                       track.bpm = 0
+                               }
                        }else{
-                               data = [];
-                       }
-                       let playlists = [];
-                       for (let i = 0; i < data.length; i++) {
-                               let obj = {
-                                       title: data[i].title,
-                                       image: data[i].picture_small,
-                                       songs: data[i].nb_tracks,
-                                       link: data[i].link
-                               };
-                               playlists.push(obj);
-                       }
-                       if (configFile.userDefined.spotifyUser){
-                               spotifyApi.clientCredentialsGrant().then(function(creds) {
-                                       spotifyApi.setAccessToken(creds.body['access_token']);
-                                       spotifyApi.getUserPlaylists(configFile.userDefined.spotifyUser, {fields: "total"}).then(data=>{
-                                               let total = data.body.total
-                                               let numPages=Math.floor((total-1)/20);
-                                               let pages = [];
-                                               let playlistList = new Array(total);
-                                               for (let offset = 0; offset<=numPages; offset++){
-                                                       pages.push(new Promise(function(resolvePage) {
-                                                               spotifyApi.getUserPlaylists(configFile.userDefined.spotifyUser, {fields: "items(images,name,owner.id,tracks.total,uri)", offset: offset*20}).then(data=>{
-                                                                       data.body.items.forEach((playlist, i)=>{
-                                                                               playlistList[(offset*20)+i] = {
-                                                                                       title: playlist.name,
-                                                                                       image: (playlist.images[0] ? playlist.images[0].url : ""),
-                                                                                       songs: playlist.tracks.total,
-                                                                                       link: playlist.uri
-                                                                               };
-                                                                       });
-                                                                       resolvePage();
-                                                               });
-                                                       }));
-                                               }
-                                               Promise.all(pages).then(()=>{
-                                                       playlists = playlists.concat(playlistList);
-                                                       logger.info(`Loaded ${playlists.length} Playlist${playlists.length>1 ? "s" : ""}`);
-                                                       socket.emit("getMePlaylistList", {playlists: playlists});
-                                               });
-                                       }).catch(err=>{
-                                               logger.error(err.stack);
-                                       });
-                               }).catch(err=>{
-                                       logger.error(err.stack);
-                               });
+                               track.bpm = 0
+                       }
+
+                       // Acquiring ReplayGain value (only if necessary)
+                       if (settings.tags.replayGain){
+                               logger.info(`[${track.artist.name} - ${track.title}] Getting track gain`);
+                               try{
+                                       var gain = await s.Deezer.legacyGetTrack(track.id)
+                                       track.replayGain = gain.gain
+                               }catch(err){
+                                       track.replayGain = 0
+                               }
                        }else{
-                               logger.info(`Loaded ${playlists.length} Playlist${playlists.length>1 ? "s" : ""}`);
-                               socket.emit("getMePlaylistList", {playlists: playlists});
+                               track.replayGain = 0
                        }
-               });
-       });
 
-       socket.on("search", function (data) {
-               data.type = data.type || "track";
-               if (["track", "playlist", "album", "artist"].indexOf(data.type) == -1) data.type = "track";
+                       if (settings.tags.discNumber && !track.discNumber){
+                               logger.info(`[${track.artist.name} - ${track.title}] Getting disc number`);
+                               var discNumber = await s.Deezer.legacyGetTrack(track.id)
+                               track.discNumber = discNumber.disk_number
+                       }
 
-               // Remove "feat."  "ft." and "&" (causes only problems)
-               data.text = data.text.replace(/ feat[\.]? /g, " ").replace(/ ft[\.]? /g, " ").replace(/\(feat[\.]? /g, " ").replace(/\(ft[\.]? /g, " ").replace(/\&/g, "");
+                       let separator = settings.multitagSeparator
+                       if (separator == "null") separator = String.fromCharCode(parseInt("\u0000",16))
 
-               Deezer.search(encodeURIComponent(data.text), data.type, function (searchObject, err) {
-                       try {
-                               socket.emit("search", {type: data.type, items: searchObject.data});
-                       } catch (e) {
-                               socket.emit("search", {type: data.type, items: []});
+                       // Autoremoves (Album Version) from the title
+                       if (settings.removeAlbumVersion){
+                               if(track.title.indexOf("Album Version")>-1){
+                                       track.title = track.title.replace(/\(Album Version\)/g,"")
+                                       track.title.trim()
+                               }
                        }
-               });
-       });
 
-       socket.on("getTrackList", function (data) {
-               if (!data.type || (["playlist", "album", "artist"].indexOf(data.type) == -1) || !data.id) {
-                       socket.emit("getTrackList", {err: -1, response: {}, id: data.id, reqType: data.type});
-                       return;
-               }
-               if (data.type == 'artist') {
-                       Deezer.getArtistAlbums(data.id, function (response, err) {
-                               if (err) {
-                                       socket.emit("getTrackList", {err: "wrong id artist", response: {}, id: data.id, reqType: data.type});
-                                       return;
+                       track.album.artist.pictureUrl = `${s.Deezer.artistPicturesHost}${track.album.artist.picture}/${settings.artworkSize}x${settings.artworkSize}-000000-80-0-0${(settings.PNGcovers ? ".png" : ".jpg")}`
+                       track.album.pictureUrl = `${s.Deezer.albumPicturesHost}${track.album.picture}/${settings.artworkSize}x${settings.artworkSize}-000000-80-0-0${(settings.PNGcovers ? ".png" : ".jpg")}`
+                       if(track.contributor){
+                               if(track.contributor.composer){
+                                       track.composerString = []
+                                       uniqueArray(track.contributor.composer, track.composerString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.composerString = track.composerString.join(separator)
                                }
-                               socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
-                       });
-               } else {
-                       let reqType = data.type.charAt(0).toUpperCase() + data.type.slice(1);
-                       Deezer["get" + reqType + "Tracks"](data.id, function (response, err) {
-                               if (err) {
-                                       socket.emit("getTrackList", {err: "wrong id "+reqType, response: {}, id: data.id, reqType: data.type});
-                                       return;
+                               if(track.contributor.musicpublisher){
+                                       track.musicpublisherString = []
+                                       uniqueArray(track.contributor.musicpublisher, track.musicpublisherString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.musicpublisherString = track.musicpublisherString.join(separator)
                                }
-                               socket.emit("getTrackList", {response: response, id: data.id, reqType: data.type});
-                       });
-               }
-       });
+                               if(track.contributor.producer){
+                                       track.producerString = []
+                                       uniqueArray(track.contributor.producer, track.producerString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.producerString = track.producerString.join(separator)
+                               }
+                               if(track.contributor.engineer){
+                                       track.engineerString = []
+                                       uniqueArray(track.contributor.engineer, track.engineerString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.engineerString = track.engineerString.join(separator)
+                               }
+                               if(track.contributor.writer){
+                                       track.writerString = []
+                                       uniqueArray(track.contributor.writer, track.writerString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.writerString = track.writerString.join(separator)
+                               }
+                               if(track.contributor.author){
+                                       track.authorString = []
+                                       uniqueArray(track.contributor.author, track.authorString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.authorString = track.authorString.join(separator)
+                               }
+                               if(track.contributor.mixer){
+                                       track.mixerString = [];
+                                       uniqueArray(track.contributor.mixer, track.mixerString, settings.removeDupedTags)
+                                       if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.mixerString = track.mixerString.join(separator)
+                               }
+                       }
 
-       socket.on("cancelDownload", function (data) {
-               if (!data.queueId) {
-                       return;
-               }
-               let cancel = false;
-               let cancelSuccess;
-               if (socket.downloadQueue[data.queueId]){
-                       cancel = true;
-                       delete socket.downloadQueue[data.queueId];
-               }
-               if (socket.currentItem && socket.currentItem.queueId == data.queueId) {
-                       cancelSuccess = Deezer.cancelDecryptTrack(data.queueId);
-                       socket.trackQueue = queue({
-                               autostart: true,
-                               concurrency: socket.trackQueue.concurrency
-                       })
-                       cancel = cancel || cancelSuccess;
-               }
-               if (cancel) {
-                       socket.emit("cancelDownload", {queueId: data.queueId});
-               }
-       });
+                       if(track.artists || track.artistsString){
+                               if (!track.artistsString){
+                                       track.artistsString = []
+                                       artistArray = []
+                                       track.artists.forEach(function(artist){
+                                               artistArray.push(artist.name)
+                                       })
+                               }else{
+                                       if (! Array.isArray(track.artistsString)){
+                                               track.artistsString = [track.artistsString,]
+                                       }
+                                       artistArray = track.artistsString
+                               }
+                               uniqueArray(artistArray, track.artistsString, settings.removeDupedTags)
+                               let posMainArtist = track.artistsString.indexOf(track.album.artist.name)
+                               if (posMainArtist !== -1 && posMainArtist !== 0 && settings.removeDupedTags){
+                                       let element = track.artistsString[posMainArtist]
+                               track.artistsString.splice(posMainArtist, 1)
+                               track.artistsString.splice(0, 0, element)
+                               }
+                               if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.artistsString = track.artistsString.join(separator)
+                       }
+                       if (track.genre){
+                               if (!(track.selectedFormat == 9 && separator==String.fromCharCode(parseInt("\u0000",16)))) track.genreString = track.genre.join(separator)
+                       }
 
-       socket.on("downloadAlreadyInQueue", function (data) {
-               if (data.id) {
-                       return;
+                       if (track.date){
+                               let date
+                               switch (settings.dateFormat){
+                                       case "0": date = `${track.date.slicedYear}-${track.date.month}-${track.date.day}`; break;
+                                       case "1": date = `${track.date.day}-${track.date.month}-${track.date.slicedYear}`; break;
+                                       case "2": date = `${track.date.month}-${track.date.day}-${track.date.slicedYear}`; break;
+                                       case "3": date = `${track.date.slicedYear}-${track.date.day}-${track.date.month}`; break;
+                                       case "4": date = `${track.date.day}${track.date.month}`; break;
+                                       default: date = `${track.date.day}${track.date.month}`; break;
+                               }
+                               track.dateString = date;
+                       }
+               }else{
+                       track.date = {year: 0,day: 0,month: 0}
                }
-               let isInQueue = checkIfAlreadyInQueue(data.id);
-               if (isInQueue) {
-                       socket.emit("downloadAlreadyInQueue", {alreadyInQueue: true, id: data.id, queueId: isInQueue});
-               } else {
-                       socket.emit("downloadAlreadyInQueue", {alreadyInQueue: false, id: data.id});
+
+               if(settings.plName && !(settings.createArtistFolder || settings.createAlbumFolder) && !settings.numplaylistbyalbum){
+                       track.trackNumber = (track.position+1).toString();
+                       track.trackTotal = settings.playlist.fullSize;
+                       track.discNumber = "1";
+                       track.discTotal = "1";
                }
-       });
 
-       socket.on("getUserSettings", function () {
-               let settings = configFile.userDefined;
-               if (!settings.downloadLocation) {
-                       settings.downloadLocation = mainFolder;
+               // Auto detect aviable track format from settings
+               if (parseInt(track.id)>0){
+                       switch(settings.maxBitrate){
+                               case "9":
+                                       track.selectedFormat = 9
+                                       track.selectedFilesize = track.filesize.flac
+                                       if (track.filesize.flac>0) break
+                                       if (!settings.fallbackBitrate) throw new Error("Song not found at desired bitrate.")
+                               case "3":
+                                       track.selectedFormat = 3
+                                       track.selectedFilesize = track.filesize.mp3_320
+                                       if (track.filesize.mp3_320>0) break
+                                       if (!settings.fallbackBitrate) throw new Error("Song not found at desired bitrate.")
+                               case "1":
+                                       track.selectedFormat = 1
+                                       track.selectedFilesize = track.filesize.mp3_128
+                                       if (track.filesize.mp3_128>0) break
+                                       if (!settings.fallbackBitrate) throw new Error("Song not found at desired bitrate.")
+                               default:
+                                       track.selectedFormat = 8
+                                       track.selectedFilesize = track.filesize.default
+                       }
+               }else{
+                       track.selectedFilesize = track.filesize
+                       track.selectedFormat = 3
                }
-               socket.emit('getUserSettings', {settings: settings});
-       });
 
-       socket.on("saveSettings", function (settings) {
-               if (settings.userDefined.downloadLocation == defaultDownloadDir) {
-                       settings.userDefined.downloadLocation = "";
-               } else {
-                       settings.userDefined.downloadLocation = path.resolve(settings.userDefined.downloadLocation + path.sep) + path.sep;
-                       mainFolder = settings.userDefined.downloadLocation;
+               // TODO: Move to a separate function
+               // Generating file name
+               if (settings.saveFullArtists && settings.multitagSeparator != null){
+                       let filename = fixName(`${track.artistsString} - ${track.title}`);
+               }else{
+                       let filename = fixName(`${track.artist.name} - ${track.title}`);
+               }
+               if (settings.filename) {
+                       filename = settingsRegex(track, settings.filename, settings.playlist, settings.saveFullArtists && settings.multitagSeparator != null, settings.paddingSize);
                }
 
-               if (settings.userDefined.queueConcurrency < 1) settings.userDefined.queueConcurrency = 1;
+               // TODO: Move to a separate function
+               // Generating file path
+               let filepath = mainFolder;
+               let artistPath;
+               if (settings.createArtistFolder || settings.createAlbumFolder) {
 
-               if (settings.userDefined.queueConcurrency != socket.trackQueue.concurrency){
-                       socket.trackQueue.concurrency = settings.userDefined.queueConcurrency;
-               }
+                       if(settings.plName){
+                               filepath += antiDot(fixName(settings.plName)) + path.sep;
+                       }
 
-               if (settings.userDefined.chartsCountry != configFile.userDefined.chartsCountry){
-                       socket.emit("setChartsCountry", {selected: settings.userDefined.chartsCountry});
-                       Deezer.getChartsTopCountry(function (charts, err) {
-                               if(err){
-                                       return;
-                               }
-                               if(charts){
-                                       charts = charts.data || [];
+                       if (settings.createArtistFolder) {
+                               if(settings.artName){
+                                       filepath += antiDot(fixName(settings.artName)) + path.sep;
                                }else{
-                                       charts = [];
-                               }
-                               let countries = [];
-                               for (let i = 0; i < charts.length; i++) {
-                                       countries.push(charts[i].title.replace("Top ", ""));
+                                       filepath += antiDot(fixName(track.album.artist.name)) + path.sep;
                                }
+                               artistPath = filepath;
+                       }
 
-                               if (countries.indexOf(settings.userDefined.chartsCountry) == -1) {
-                                       socket.emit("getChartsTrackListByCountry", {err: "Country not found"});
-                                       return;
+                       if (settings.createAlbumFolder) {
+                               if(settings.artName){
+                                       filepath += antiDot(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,track.date.year,track.recordType,track.album.explicit,track.publisher,track.genre)) + path.sep;
+                               }else{
+                                       filepath += antiDot(settingsRegexAlbum(settings.foldername,track.album.artist.name,track.album.title,track.date.year,track.recordType,track.album.explicit,track.publisher,track.genre)) + path.sep;
                                }
+                       }
+               } else if (settings.plName) {
+                       filepath += antiDot(fixName(settings.plName)) + path.sep;
+               } else if (settings.artName) {
+                       filepath += antiDot(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,track.date.year,track.recordType,track.album.explicit,track.publisher,track.genre)) + path.sep;
+               }
+               let coverpath = filepath;
+               if (track.discTotal > 1 && (settings.artName || settings.createAlbumFolder) && settings.createCDFolder){
+                       filepath += `CD${track.discNumber +  path.sep}`
+               }
+               let writePath;
 
-                               let playlistId = charts[countries.indexOf(settings.userDefined.chartsCountry)].id;
+               if(track.selectedFormat == 9){
+                       writePath = filepath + filename + '.flac';
+               }else{
+                       writePath = filepath + filename + '.mp3';
+               }
 
-                               Deezer.getPlaylistTracks(playlistId, function (tracks, err) {
-                                       if (err) {
-                                               socket.emit("getChartsTrackListByCountry", {err: err});
-                                               return;
-                                       }
-                                       socket.emit("getChartsTrackListByCountry", {
-                                               playlist: charts[countries.indexOf(settings.userDefined.chartsCountry)],
-                                               tracks: tracks.data
-                                       });
-                               });
-                       });
+               if ((settings.syncedlyrics || settings.tags.unsynchronisedLyrics) && track.lyricsId>0){
+                       let lyr = await s.Deezer.getLyrics(track.id)
+                       track.syncLyrics = lyr.syncLyrics
+                       track.unsyncLyrics = lyr.unsyncLyrics
                }
 
-               configFile.userDefined = settings.userDefined;
-               fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2), function (err) {
-                       if (err) return;
-                       logger.info("Settings updated");
-                       initFolders();
-               });
-       });
+               if(track.syncLyrics && settings.syncedlyrics){
+                       fs.outputFile(writePath.substring(0,writePath.lastIndexOf('.'))+".lrc",track.syncLyrics,function(){});
+               }
 
-       function downloadTrack(t, settings, altmetadata, callback) {
-               if (!socket.downloadQueue[t.queueId]) {
-                       logger.error("Not in queue");
-                       callback(new Error("Not in queue"), `${t.id} | ${t.artist} - ${t.name}`);
-                       return;
+               track.playlistData = [0,""]
+               if (settings.createM3UFile && (settings.plName || settings.albName)) {
+                       if (track.position){
+                               track.playlistData = [parseInt(track.position), writePath];
+                       }else{
+                               track.playlistData = [track.trackNumber-1, writePath];
+                       }
                }
-               if (t.id == 0){
-                       logger.error("Failed to download track: Wrong ID");
-                       callback(new Error("Failed to download track: Wrong ID"), `${t.id} | ${t.artist} - ${t.name}`);
+               if (fs.existsSync(writePath)) {
+                       logger.info(`[${track.artist.name} - ${track.title}] Already downloaded`);
                        return;
+               }else{
+                       logger.info(`[${track.artist.name} - ${track.title}] Downloading file to ${writePath}`);
                }
-               let temp1 = new Promise((resolve, reject)=>{
-                       if (!settings.trackInfo){
-                               logger.info("Getting track data");
-                               Deezer.getTrack(t.id, settings.hifi, function (trackInfo, err) {
-                                       if (err) {
-                                               if(t.fallback){
-                                                       logger.warn("Failed to download track, falling on alternative");
-                                                       t.id = t.fallback
-                                                       t.fallback = 0
-                                                       downloadTrack(t, settings, null, function(err){
-                                                               callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                                       });
-                                               }else if(!t.searched){
-                                                       logger.warn("Failed to download track, searching for alternative");
-                                                       Deezer.track2ID(t.artist, t.name, data=>{
-                                                               t.searched = true;
-                                                               t.id = data.id;
-                                                               t.artist = data.artist;
-                                                               t.name = data.name;
-                                                               downloadTrack(t, settings, null, function(err){
-                                                                       callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                                               });
-                                                       });
-                                               }else{
-                                                       logger.error("Failed to download track: "+ err);
-                                                       callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                               }
-                                               return;
-                                       }
-                                       resolve(trackInfo);
-                               });
+               // Get cover image
+               if (track.album.pictureUrl) {
+                       let imgPath;
+                       //If its not from an album but a playlist.
+                       if(!(settings.albName || settings.createAlbumFolder)){
+                               imgPath = coverArtFolder + (track.album.barcode ? fixName(track.album.barcode) : fixName(`${track.album.artist.name} - ${track.album.title}`))+(settings.PNGcovers ? ".png" : ".jpg")
                        }else{
-                               resolve(settings.trackInfo);
+                               if (settings.saveArtwork)
+                                       imgPath = coverpath + settingsRegexCover(settings.coverImageTemplate,track.album.artist.name,track.album.title)+(settings.PNGcovers ? ".png" : ".jpg")
+                               else
+                                       imgPath = coverArtFolder + fixName(track.album.barcode ? fixName(track.album.barcode) : fixName(`${track.album.artist.name} - ${track.album.title}`))+(settings.PNGcovers ? ".png" : ".jpg")
                        }
-               })
-               temp1.then(data=>{
-                       let track = data;
-                       track.trackSocket = socket;
-                       logger.info("Getting album data");
-                       let temp2 = new Promise((resolve, reject)=>{
-                               if (!settings.albumInfo){
-                                       Deezer.getAlbum(track["ALB_ID"], function(res, err){
-                                               if(err){
-                                                       if(t.fallback){
-                                                               logger.warn("Failed to download track, falling on alternative");
-                                                               t.id = t.fallback
-                                                               t.fallback = 0
-                                                               downloadTrack(t, settings, null, function(err){
-                                                                       callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                                               });
-                                                       }else if(!t.searched){
-                                                               logger.warn("Failed to download track, searching for alternative");
-                                                               Deezer.track2ID(t.artist, t.name, data=>{
-                                                                       t.searched = true;
-                                                                       t.id = data.id;
-                                                                       t.artist = data.artist;
-                                                                       t.name = data.name;
-                                                                       downloadTrack(t, settings, null, function(err){
-                                                                               callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                                                       });
-                                                               });
-                                                       }else{
-                                                               logger.error("Failed to download track: "+ err);
-                                                               callback(new Error("Album does not exists."), `${t.id} | ${t.artist} - ${t.name}`);
-                                                       }
-                                                       return;
-                                               }
-                                               resolve(res);
-                                       })
-                               }else{
-                                       resolve(settings.albumInfo)
+                       if(fs.existsSync(imgPath)){
+                               track.album.picturePath = (imgPath).replace(/\\/g, "/")
+                               logger.info(`[${track.artist.name} - ${track.title}] Starting the download process CODE:1`)
+                       }else{
+                               try{
+                                       var body = await request.get(track.album.pictureUrl, {strictSSL: false,encoding: 'binary'})
+                                       fs.outputFileSync(imgPath,body,'binary')
+                                       track.album.picturePath = (imgPath).replace(/\\/g, "/")
+                                       logger.info(`[${track.artist.name} - ${track.title}] Starting the download process CODE:2`)
+                               }catch(error){
+                                       logger.error(`[${track.artist.name} - ${track.title}] Cannot download Album Image: ${error}`)
+                                       logger.error(`Album art link: ${track.album.pictureUrl}`)
+                                       track.album.pictureUrl = undefined
+                                       track.album.picturePath = undefined
                                }
-                       });
-                       temp2.then(res=>{
-                               settings = settings || {};
-                               let ajson = res;
-                               let totalDiskNumber;
-                               let temp3;
-                               if (settings.partOfSet){
-                                       logger.info("Getting total disk number data");
-                                       temp3 = new Promise((resolve, reject) =>{
-                                               Deezer.getATrack(ajson.tracks.data[ajson.tracks.data.length-1].id, function(tres){
-                                                       totalDiskNumber = tres.disk_number;
-                                                       resolve();
-                                               });
-                                       })
-                               }else{
-                                       temp3 = new Promise((resolve, reject) =>{
-                                               resolve()
-                                       })
+                       }
+               }else{
+                       track.album.pictureUrl = undefined
+                       logger.info(`[${track.artist.name} - ${track.title}] Starting the download process CODE:3`)
+               }
+
+               // Get Artist Image
+               if (parseInt(this.id)>0 && track.album.artist.picture && settings.saveArtworkArtist) {
+                       let imgPath;
+                       if(settings.createArtistFolder){
+                               imgPath = artistPath + antiDot(settingsRegexArtistCover(settings.artistImageTemplate,track.album.artist.name))+(settings.PNGcovers ? ".png" : ".jpg");
+                               if(!fs.existsSync(imgPath)){
+                                       try{
+                                               var body = await request.get(track.album.artist.pictureUrl, {strictSSL: false,encoding: 'binary'})
+                                               if (body.indexOf("unauthorized")>-1) throw new Error("Unauthorized")
+                                               fs.outputFileSync(imgPath,body,'binary')
+                                               logger.info(`[${track.artist.name} - ${track.title}] Saved Artist Image`)
+                                       }catch(err){
+                                               logger.error(`[${track.artist.name} - ${track.title}] Cannot download Artist Image: ${err}`)
+                                       }
+                               }
+                       }
+               }
+
+               let tempPath
+               if(parseInt(track.id)>0)
+                       tempPath = `${filepath}${track.id}_${track.selectedFormat}.temp`
+               else
+                       tempPath = writePath
+
+               logger.info(`[${track.artist.name} - ${track.title}] Downloading track`)
+               var downloadingPromise = new Promise((resolve, reject)=>{
+                       let req = requestOld.get({url: track.getDownloadUrl(track.selectedFormat), strictSSL: false, headers: s.Deezer.httpHeaders, encoding: 'binary'}, function (error, response, body) {
+                               if (error){
+                                       logger.error(`[${track.artist.name} - ${track.title}] Downloading error: ${error}`)
+                                       reject("Downloading error: "+error)
+                                       return false
+                               }
+                               if (!s.downloadQueue[queueId]){
+                                       fs.remove(tempPath)
+                                       reject("Not in Queue")
+                                       return false
                                }
-                               temp3.then(()=>{
-                                       let metadata = parseMetadata(track, ajson, totalDiskNumber, settings, t.index, altmetadata);
-                                       let filename = fixName(`${metadata.artist} - ${metadata.title}`);
-                                       if (settings.filename) {
-                                               filename = fixName(settingsRegex(metadata, settings.filename, settings.playlist));
+                               if (body.length == 0){
+                                       logger.error(`[${track.artist.name} - ${track.title}] Downloading error: Track is Empty`)
+                                       fs.remove(tempPath)
+                                       reject("Track is Empty")
+                                       return false
+                               }
+                               logger.info(`[${track.artist.name} - ${track.title}] Decrypting track`)
+                               var decryptedSource = s.Deezer.decryptDownload(Buffer.from(body, 'binary'), track.id)
+                               try{
+                                       fs.outputFileSync(tempPath,decryptedSource)
+                                       resolve()
+                               }catch(err){
+                                       logger.error(`[${track.artist.name} - ${track.title}] Decryption error: ${err}`)
+                                       reject(err)
+                                       return false
+                               }
+                       }).on("data", function(data) {
+                               if (!s.downloadQueue[queueId]){
+                                       reject("Not in Queue")
+                                       return false
+                               }
+                       })
+                       if((s.downloadQueue[queueId]) && s.downloadQueue[queueId].type == "track"){
+                               let chunkLength = 0
+                               req.on("data", function(data) {
+                                       if (!s.downloadQueue[queueId]){
+                                               reject("Not in Queue")
                                        }
-                                       let filepath = mainFolder;
-                                       if (settings.createArtistFolder || settings.createAlbumFolder) {
-                                               if(settings.plName){
-                                                       filepath += antiDot(fixName(settings.plName)) + path.sep;
+                                       chunkLength += data.length
+                                       try{
+                                               if (!s.downloadQueue[queueId].percentage) {
+                                                       s.downloadQueue[queueId].percentage = 0
                                                }
-                                               if (settings.createArtistFolder) {
-                                                       if(settings.artName){
-                                                               filepath += antiDot(fixName(settings.artName)) + path.sep;
-                                                       }else{
-                                                               filepath += antiDot(fixName(metadata.artist)) + path.sep;
-                                                       }
+                                               let complete = track.selectedFilesize
+                                               let percentage = (chunkLength / complete) * 100;
+                                               if ((percentage - s.downloadQueue[queueId].percentage > 1) || (chunkLength == complete)) {
+                                                       s.downloadQueue[queueId].percentage = percentage
+                                                       s.emit("downloadProgress", {
+                                                               queueId: queueId,
+                                                               percentage: s.downloadQueue[queueId].percentage-5
+                                                       })
                                                }
+                                       }catch(err){}
+                               })
+                       }
+               })
 
-                                               if (settings.createAlbumFolder) {
-                                                       if(settings.artName){
-                                                               filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,metadata.year,metadata.rtype))) + path.sep;
-                                                       }else{
-                                                               filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,metadata.performerInfo,metadata.album,metadata.year,metadata.rtype))) + path.sep;
-                                                       }
-                                               }
-                                       } else if (settings.plName) {
-                                               filepath += antiDot(fixName(settings.plName)) + path.sep;
-                                       } else if (settings.artName) {
-                                               filepath += antiDot(fixName(settingsRegexAlbum(settings.foldername,settings.artName,settings.albName,metadata.year,metadata.rtype))) + path.sep;
+
+               await downloadingPromise
+
+               logger.info(`[${track.artist.name} - ${track.title}] Adding Tags`)
+               if (parseInt(track.id)>0){
+                       if(track.selectedFormat == 9){
+                               let flacComments = [];
+                               if (settings.tags.title)
+                                       flacComments.push('TITLE=' + track.title);
+                               if (settings.tags.album)
+                                       flacComments.push('ALBUM=' + track.album.title);
+                               if (settings.tags.albumArtist)
+                                       flacComments.push('ALBUMARTIST=' + track.album.artist.name);
+                               if (settings.tags.trackNumber)
+                                       flacComments.push('TRACKNUMBER=' + track.trackNumber);
+                               if (settings.tags.discNumber)
+                                       flacComments.push('DISCNUMBER=' + track.discNumber);
+                               if (settings.tags.trackTotal)
+                                       flacComments.push('TRACKTOTAL=' + track.trackTotal);
+                               if (settings.tags.explicit)
+                                       flacComments.push('ITUNESADVISORY=' + track.explicit);
+                               if (settings.tags.isrc)
+                                       flacComments.push('ISRC=' + track.ISRC);
+                               if (settings.tags.artist && track.artistsString)
+                                       if (Array.isArray(track.artistsString)){
+                                               track.artistsString.forEach(x=>{
+                                                       flacComments.push('ARTIST=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('ARTIST=' + track.artistsString);
                                        }
-                                       let writePath;
-                                       if(track.format == 9){
-                                               writePath = filepath + filename + '.flac';
+                               if (settings.tags.discTotal)
+                                       flacComments.push('DISCTOTAL='+track.discTotal);
+                               if (settings.tags.length)
+                                       flacComments.push('LENGTH=' + track.duration);
+                               if (settings.tags.barcode && track.album.barcode)
+                                       flacComments.push('BARCODE=' + track.album.barcode);
+                               if (track.unsyncLyrics && settings.tags.unsynchronisedLyrics)
+                                       flacComments.push('LYRICS='+track.unsyncLyrics.lyrics);
+                               if (track.genreString && settings.tags.genre)
+                                       if (Array.isArray(track.genreString)){
+                                               track.genreString.forEach(x=>{
+                                                       flacComments.push('GENRE=' + x);
+                                               });
                                        }else{
-                                               writePath = filepath + filename + '.mp3';
+                                               flacComments.push('GENRE=' + track.genreString);
                                        }
-                                       if(track["LYRICS_SYNC_JSON"] && settings.syncedlyrics){
-                                               let lyricsbuffer = "";
-                                               for(let i=0;i<track["LYRICS_SYNC_JSON"].length;i++){
-                                                       if(track["LYRICS_SYNC_JSON"][i].lrc_timestamp){
-                                                               lyricsbuffer += track["LYRICS_SYNC_JSON"][i].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
-                                                       }else if(i+1 < track["LYRICS_SYNC_JSON"].length){
-                                                               lyricsbuffer += track["LYRICS_SYNC_JSON"][i+1].lrc_timestamp+track["LYRICS_SYNC_JSON"][i].line+"\r\n";
-                                                       }
-                                               }
-                                               fs.outputFile(writePath.substring(0,writePath.lastIndexOf('.'))+".lrc",lyricsbuffer,function(){});
+                               if (track.copyright && settings.tags.copyright)
+                                       flacComments.push('COPYRIGHT=' + track.copyright);
+                               if (0 < parseInt(track.date.year)){
+                                       if (settings.tags.year)
+                                               flacComments.push('YEAR=' + track.date.year);
+                                       if (settings.tags.date)
+                                       flacComments.push('DATE=' + track.dateString);
+                               }
+                               if (0 < parseInt(track.bpm) && settings.tags.bpm)
+                                       flacComments.push('BPM=' + track.bpm);
+                               if(track.publisher && settings.tags.publisher)
+                                       flacComments.push('PUBLISHER=' + track.publisher);
+                               if(track.composerString && settings.tags.composer)
+                                       if (Array.isArray(track.composerString)){
+                                               track.composerString.forEach(x=>{
+                                                       flacComments.push('COMPOSER=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('COMPOSER=' + track.composerString);
                                        }
-                                       if (settings.createM3UFile && (settings.plName || settings.albName)) {
-                                               if (!settings.numplaylistbyalbum){
-                                                       t.playlistData = [splitNumber(metadata.trackNumber,false)-1, filename + (track.format == 9 ? ".flac" : ".mp3")];
-                                               }else{
-                                                       t.playlistData = [t.index, filename + (track.format == 9 ? ".flac" : ".mp3")];
-                                               }
+                               if(track.musicpublisherString && settings.tags.musicpublisher)
+                                       if (Array.isArray(track.musicpublisherString)){
+                                               track.musicpublisherString.forEach(x=>{
+                                                       flacComments.push('ORGANIZATION=' + x);
+                                               });
                                        }else{
-                                               t.playlistData = [0,""];
+                                               flacComments.push('ORGANIZATION=' + track.musicpublisherString);
                                        }
-                                       if (fs.existsSync(writePath)) {
-                                               logger.info("Already downloaded: " + metadata.artist + ' - ' + metadata.title);
-                                               callback(null, t.playlistData);
-                                               return;
+                               if(track.mixerString && settings.tags.mixer)
+                                       if (Array.isArray(track.mixerString)){
+                                               track.mixerString.forEach(x=>{
+                                                       flacComments.push('MIXER=' + x);
+                                               });
                                        }else{
-                                               logger.info('Downloading file to ' + writePath);
+                                               flacComments.push('MIXER=' + track.mixerString);
                                        }
-                                       //Get image
-                                       let temp4 = new Promise((resolve, reject)=>{
-                                               if (metadata.image) {
-                                                       let imgPath;
-                                                       //If its not from an album but a playlist.
-                                                       if(!(settings.albName || settings.createAlbumFolder)){
-                                                               imgPath = coverArtFolder + fixName(metadata.ISRC) + ".jpg";
-                                                       }else{
-                                                               if (settings.saveArtwork)
-                                                                       imgPath = filepath + "folder.jpg";
-                                                               else
-                                                                       imgPath = coverArtFolder + fixName(settings.artName+" - "+settings.albName) + ".jpg";
-                                                       }
-                                                       if(fs.existsSync(imgPath)){
-                                                               metadata.imagePath = (imgPath).replace(/\\/g, "/");
-                                                               logger.info("Starting the download process CODE:1");
-                                                               resolve();
-                                                       }else{
-                                                               request.get(metadata.image, {encoding: 'binary'}, function(error,response,body){
-                                                                       if(error){
-                                                                               logger.error(error.stack);
-                                                                               metadata.image = undefined;
-                                                                               metadata.imagePath = undefined;
-                                                                               return;
-                                                                       }
-                                                                       fs.outputFile(imgPath,body,'binary',function(err){
-                                                                               if(err){
-                                                                                       logger.error(err.stack);
-                                                                               metadata.image = undefined;
-                                                                               metadata.imagePath = undefined;
-                                                                                       return;
-                                                                               }
-                                                                               metadata.imagePath = (imgPath).replace(/\\/g, "/");
-                                                                               logger.info("Starting the download process CODE:2");
-                                                                               resolve();
-                                                                       })
-                                                               });
-                                                       }
-                                               }else{
-                                                       metadata.image = undefined;
-                                                       logger.info("Starting the download process CODE:3");
-                                                       resolve();
+                               if(track.authorString && settings.tags.author)
+                                       if (Array.isArray(track.authorString)){
+                                               track.authorString.forEach(x=>{
+                                                       flacComments.push('AUTHOR=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('AUTHOR=' + track.authorString);
+                                       }
+                               if(track.writerString && settings.tags.writer)
+                                       if (Array.isArray(track.writerString)){
+                                               track.writerString.forEach(x=>{
+                                                       flacComments.push('WRITER=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('WRITER=' + track.writerString);
+                                       }
+                               if(track.engineerString && settings.tags.engineer)
+                                       if (Array.isArray(track.engineerString)){
+                                               track.engineerString.forEach(x=>{
+                                                       flacComments.push('ENGINEER=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('ENGINEER=' + track.engineerString);
+                                       }
+                               if(track.producerString && settings.tags.producer)
+                                       if (Array.isArray(track.producerString)){
+                                               track.producerString.forEach(x=>{
+                                                       flacComments.push('PRODUCER=' + x);
+                                               });
+                                       }else{
+                                               flacComments.push('PRODUCER=' + track.producerString);
+                                       }
+                               if(track.replayGain && settings.tags.replayGain)
+                                       flacComments.push('REPLAYGAIN_TRACK_GAIN=' + track.replayGain);
+
+                               const reader = fs.createReadStream(tempPath);
+                               const writer = fs.createWriteStream(writePath);
+                               let processor = new mflac.Processor({parseMetaDataBlocks: true});
+                               let vendor = 'reference libFLAC 1.2.1 20070917';
+                               let cover = null;
+                               if(track.album.picturePath && settings.tags.cover){
+                                       cover = fs.readFileSync(track.album.picturePath)
+                               }
+                               let mdbVorbisPicture
+                               let mdbVorbisComment
+                               processor.on('preprocess', (mdb) => {
+                                       // Remove existing VORBIS_COMMENT and PICTURE blocks, if any.
+                                       if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type) {
+                                               mdb.remove();
+                                       } else if (mflac.Processor.MDB_TYPE_PICTURE === mdb.type) {
+                                               mdb.remove();
+                                       }
+                                       if (mdb.isLast) {
+                                               if(cover){
+                                                       mdbVorbisPicture = mflac.data.MetaDataBlockPicture.create(true, 3, `image/${(settings.PNGcovers ? "png" : "jpeg")}`, '', settings.artworkSize, settings.artworkSize, 24, 0, cover);
                                                }
-                                       })
-                                       temp4.then(()=>{
-                                               let tempPath = writePath+".temp";
-                                               logger.info("Downloading and decrypting");
-                                               Deezer.decryptTrack(tempPath, track, t.queueId, function (err) {
-                                                       if (err && err.message == "aborted") {
-                                                               logger.info("Track got aborted");
-                                                               callback(null, t.playlistData);
-                                                               return;
-                                                       }
-                                                       if (err) {
-                                                               if (t.fallback){
-                                                                       logger.error("Failed to download: " + metadata.artist + " - " + metadata.title+", falling on alternative");
-                                                                       t.id = t.fallback
-                                                                       t.fallback = 0
-                                                                       downloadTrack(t, settings, metadata, callback);
-                                                               }else if(!t.searched){
-                                                                       logger.warn("Failed to download track, searching for alternative");
-                                                                       Deezer.track2ID(t.artist, t.name, data=>{
-                                                                               t.searched = true;
-                                                                               t.id = data.id;
-                                                                               t.artist = data.artist;
-                                                                               t.name = data.name;
-                                                                               downloadTrack(t, settings, null, function(err){
-                                                                                       callback(err, `${t.id} | ${t.artist} - ${t.name}`);
-                                                                               });
-                                                                       });
-                                                               }else{
-                                                                       logger.error("Failed to download: " + metadata.artist + " - " + metadata.title);
-                                                                       callback(err, `${t.id} | ${t.artist} - ${t.name}`)
-                                                               }
-                                                               return;
-                                                       }
-                                                       logger.info("Downloaded: " + metadata.artist + " - " + metadata.title);
-                                                       metadata.artist = [];
-                                                       artistArray = []
-                                                       track['ARTISTS'].forEach(function(artist){
-                                                               artistArray.push(artist['ART_NAME']);
-                                                       });
-                                                       Array.from(new Set(artistArray)).forEach(function(artist){
-                                                               if(metadata.artist.indexOf(artist) == -1)
-                                                                       metadata.artist.push(artist);
-                                                       });
-                                                       let separator = settings.multitagSeparator;
-                                                       if (separator == "null") separator = String.fromCharCode(parseInt("\u0000",16));
-                                                       if (track.format != 9) metadata.artist = metadata.artist.join(separator);
-
-                                                       if(track.format == 9){
-                                                               let flacComments = [
-                                                                       'TITLE=' + metadata.title,
-                                                                       'ALBUM=' + metadata.album,
-                                                                       'ALBUMARTIST=' + metadata.performerInfo,
-                                                                       'TRACKNUMBER=' + splitNumber(metadata.trackNumber,false),
-                                                                       'DISCNUMBER=' + splitNumber(metadata.partOfSet,false),
-                                                                       'TRACKTOTAL=' + splitNumber(metadata.trackNumber,true),
-                                                                       'ITUNESADVISORY=' + metadata.explicit,
-                                                                       'ISRC=' + metadata.ISRC
-                                                               ];
-                                                               metadata.artist.forEach(x=>{
-                                                                       flacComments.push('ARTIST=' + x);
-                                                               })
-                                                               if (settings.partOfSet)
-                                                                       flacComments.push('DISCTOTAL='+splitNumber(metadata.partOfSet,true))
-                                                               if(settings.extendedTags){
-                                                                       flacComments.push(
-                                                                               'LENGTH=' + metadata.length,
-                                                                               'BARCODE=' + metadata.BARCODE
-                                                                       );
-                                                               }
-                                                               if(metadata.unsynchronisedLyrics){
-                                                                       flacComments.push('LYRICS='+metadata.unsynchronisedLyrics.lyrics);
-                                                               }
-                                                               if(metadata.genre){
-                                                                       metadata.genre.forEach(x=>{
-                                                                               flacComments.push('GENRE=' + x);
-                                                                       })
-                                                               }
-                                                               if(metadata.copyright){
-                                                                       flacComments.push('COPYRIGHT=' + metadata.copyright);
-                                                               }
-                                                               if (0 < parseInt(metadata.year)) {
-                                                                       flacComments.push('YEAR=' + metadata.year);
-                                                               }
-                                                               if (0 < parseInt(metadata.bpm)) {
-                                                                       flacComments.push('BPM=' + metadata.bpm);
-                                                               }
-                                                               if(metadata.composer){
-                                                                       flacComments.push('COMPOSER=' + metadata.composer);
-                                                               }
-                                                               if(metadata.publisher){
-                                                                       flacComments.push('ORGANIZATION=' + metadata.publisher);
-                                                               }
-                                                               if(metadata.mixer){
-                                                                       flacComments.push('MIXER=' + metadata.mixer);
-                                                               }
-                                                               if(metadata.author){
-                                                                       flacComments.push('AUTHOR=' + metadata.author);
-                                                               }
-                                                               if(metadata.writer){
-                                                                       flacComments.push('WRITER=' + metadata.writer);
-                                                               }
-                                                               if(metadata.engineer){
-                                                                       flacComments.push('ENGINEER=' + metadata.engineer);
-                                                               }
-                                                               if(metadata.producer){
-                                                                       flacComments.push('PRODUCER=' + metadata.producer);
-                                                               }
-                                                               if(metadata.trackgain){
-                                                                       flacComments.push('REPLAYGAIN_TRACK_GAIN=' + metadata.trackgain);
-                                                               }
-                                                               const reader = fs.createReadStream(tempPath);
-                                                               const writer = fs.createWriteStream(writePath);
-                                                               let processor = new mflac.Processor({parseMetaDataBlocks: true});
-                                                               let vendor = 'reference libFLAC 1.2.1 20070917';
-                                                               let cover = null;
-                                                               if(metadata.imagePath){
-                                                                       cover = fs.readFileSync(metadata.imagePath);
-                                                               }
-                                                               let mdbVorbisPicture;
-                                                               let mdbVorbisComment;
-                                                               processor.on('preprocess', (mdb) => {
-                                                                       // Remove existing VORBIS_COMMENT and PICTURE blocks, if any.
-                                                                       if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type) {
-                                                                               mdb.remove();
-                                                                       } else if (mflac.Processor.MDB_TYPE_PICTURE === mdb.type) {
-                                                                               mdb.remove();
-                                                                       }
-                                                                       if (mdb.isLast) {
-                                                                               let res = 0;
-                                                                               if(settings.artworkSize.includes("1400")){
-                                                                                       res = 1400;
-                                                                               }else if(settings.artworkSize.includes("1200")){
-                                                                                       res = 1200;
-                                                                               }else if(settings.artworkSize.includes("1000")){
-                                                                                       res = 1000;
-                                                                               }else if(settings.artworkSize.includes("800")){
-                                                                                       res = 800;
-                                                                               }else if(settings.artworkSize.includes("500")){
-                                                                                       res = 500;
-                                                                               }
-                                                                               if(cover){
-                                                                                       mdbVorbisPicture = mflac.data.MetaDataBlockPicture.create(true, 3, 'image/jpeg', '', res, res, 24, 0, cover);
-                                                                               }
-                                                                               mdbVorbisComment = mflac.data.MetaDataBlockVorbisComment.create(false, vendor, flacComments);
-                                                                               mdb.isLast = false;
-                                                                       }
-                                                               });
-                                                               processor.on('postprocess', (mdb) => {
-                                                                       if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type && null !== mdb.vendor) {
-                                                                               vendor = mdb.vendor;
-                                                                       }
-                                                                       if (mdbVorbisPicture && mdbVorbisComment) {
-                                                                               processor.push(mdbVorbisComment.publish());
-                                                                               processor.push(mdbVorbisPicture.publish());
-                                                                       }else if(mdbVorbisComment){
-                                                                               processor.push(mdbVorbisComment.publish());
-                                                                       }
-                                                               });
-                                                               reader.on('end', () => {
-                                                                       fs.remove(tempPath);
-                                                               });
-                                                               reader.pipe(processor).pipe(writer);
-                                                       }else{
-                                                               const songBuffer = fs.readFileSync(tempPath);
-                                                               const writer = new ID3Writer(songBuffer);
-                                                               writer.setFrame('TIT2', metadata.title)
-                                                               .setFrame('TPE1', [metadata.artist])
-                                                               .setFrame('TALB', metadata.album)
-                                                               .setFrame('TPE2', metadata.performerInfo)
-                                                               .setFrame('TRCK', (settings.partOfSet ? metadata.trackNumber : splitNumber(metadata.trackNumber,false)))
-                                                               .setFrame('TPOS', (settings.partOfSet ? metadata.partOfSet : splitNumber(metadata.partOfSet,false)))
-                                                               .setFrame('TSRC', metadata.ISRC);
-                                                               if (settings.extendedTags){
-                                                                       writer.setFrame('TLEN', metadata.length)
-                                                                       .setFrame('TXXX', {
-                                                                               description: 'BARCODE',
-                                                                               value: metadata.BARCODE
-                                                                       })
-                                                               }
-                                                               if(metadata.imagePath){
-                                                                       const coverBuffer = fs.readFileSync(metadata.imagePath);
-                                                                       writer.setFrame('APIC', {
-                                                                               type: 3,
-                                                                               data: coverBuffer,
-                                                                               description: ''
-                                                                       });
-                                                               }
-                                                               if(metadata.unsynchronisedLyrics){
-                                                                       writer.setFrame('USLT', metadata.unsynchronisedLyrics);
-                                                               }
-                                                               if(metadata.publisher){
-                                                                       writer.setFrame('TPUB', metadata.publisher);
-                                                               }
-                                                               if(metadata.genre){
-                                                                       writer.setFrame('TCON', [metadata.genre]);
-                                                               }
-                                                               if(metadata.copyright){
-                                                                       writer.setFrame('TCOP', metadata.copyright);
-                                                               }
-                                                               if (0 < parseInt(metadata.year)) {
-                                                                       writer.setFrame('TYER', metadata.year);
-                                                               }
-                                                               if (0 < parseInt(metadata.bpm)) {
-                                                                       writer.setFrame('TBPM', metadata.bpm);
-                                                               }
-                                                               if(metadata.composer){
-                                                                       writer.setFrame('TCOM', [metadata.composer]);
-                                                               }
-                                                               if(metadata.trackgain){
-                                                                       writer.setFrame('TXXX', {
-                                                                               description: 'REPLAYGAIN_TRACK_GAIN',
-                                                                               value: metadata.trackgain
-                                                                       });
-                                                               }
-                                                               writer.addTag();
-                                                               const taggedSongBuffer = Buffer.from(writer.arrayBuffer);
-                                                               fs.writeFileSync(writePath, taggedSongBuffer);
-                                                               fs.remove(tempPath);
-                                                       }
-                                                       callback(null, t.playlistData);
-                                               })
-                                       })
-                               })
-                       })
-               })
-       }
-
-       function checkIfAlreadyInQueue(id) {
-               let exists = false;
-               Object.keys(socket.downloadQueue).forEach(x=>{
-                       if (socket.downloadQueue[x].id == id) {
-                               exists = socket.downloadQueue[i].queueId;
+                                               mdbVorbisComment = mflac.data.MetaDataBlockVorbisComment.create(!cover, vendor, flacComments);
+                                               mdb.isLast = false;
+                                       }
+                               });
+                               processor.on('postprocess', (mdb) => {
+                                       if (mflac.Processor.MDB_TYPE_VORBIS_COMMENT === mdb.type && null !== mdb.vendor) {
+                                               vendor = mdb.vendor;
+                                       }
+                                       if (mdbVorbisPicture && mdbVorbisComment) {
+                                                       processor.push(mdbVorbisComment.publish());
+                                                       processor.push(mdbVorbisPicture.publish());
+                                               }else if(mdbVorbisComment){
+                                                       processor.push(mdbVorbisComment.publish());
+                                       }
+                               });
+                               reader.on('end', () => {
+                                       fs.remove(tempPath);
+                               });
+                               await reader.pipe(processor).pipe(writer);
+                       }else{
+                               const songBuffer = fs.readFileSync(tempPath);
+                               const writer = new ID3Writer(songBuffer);
+                               if (settings.tags.title)
+                                       writer.setFrame('TIT2', track.title)
+                               if (settings.tags.artist)
+                                       writer.setFrame('TPE1', [track.artistsString])
+                               if (settings.tags.album)
+                                       writer.setFrame('TALB', track.album.title)
+                               if (settings.tags.albumArtist && track.album.artist)
+                                       writer.setFrame('TPE2', track.album.artist.name)
+                               if (settings.tags.trackNumber)
+                                       writer.setFrame('TRCK', (settings.tags.trackTotal ? track.trackNumber+"/"+track.trackTotal : track.trackNumber))
+                               if (settings.tags.discNumber)
+                                       writer.setFrame('TPOS', (settings.tags.discTotal ? track.discNumber+"/"+track.discTotal : track.discNumber))
+                               if (settings.tags.isrc)
+                                       writer.setFrame('TSRC', track.ISRC);
+
+                               if (settings.tags.length)
+                                       writer.setFrame('TLEN', track.duration);
+                               if (settings.tags.barcode && track.album.barcode)
+                                       writer.setFrame('TXXX', {
+                                               description: 'BARCODE',
+                                               value: track.album.barcode
+                                       });
+                               if(track.album.picturePath && settings.tags.cover){
+                                       const coverBuffer = fs.readFileSync(track.album.picturePath);
+                                       writer.setFrame('APIC', {
+                                               type: 3,
+                                               data: coverBuffer,
+                                               description: ''
+                                       });
+                               }
+                               if(track.unsyncLyrics && settings.tags.unsynchronisedLyrics)
+                                       writer.setFrame('USLT', track.unsyncLyrics);
+                               if(track.publisher && settings.tags.publisher)
+                                       writer.setFrame('TPUB', track.publisher);
+                               if(track.genreString && settings.tags.genre)
+                                       writer.setFrame('TCON', [track.genreString]);
+                               if(track.copyright && settings.tags.copyright)
+                                       writer.setFrame('TCOP', track.copyright);
+                               if (0 < parseInt(track.date.year)) {
+                                       if (settings.tags.date)
+                                               writer.setFrame('TDAT', track.dateString);
+                                       if (settings.tags.year)
+                                               writer.setFrame('TYER', track.date.year);
+                               }
+                               if (0 < parseInt(track.bpm) && settings.tags.bpm)
+                                       writer.setFrame('TBPM', track.bpm);
+                               if(track.composerString && settings.tags.composer)
+                                       writer.setFrame('TCOM', [track.composerString]);
+                               if(track.replayGain && settings.tags.replayGain)
+                                       writer.setFrame('TXXX', {
+                                               description: 'REPLAYGAIN_TRACK_GAIN',
+                                               value: track.replayGain
+                                       });
+                               writer.addTag();
+                               const taggedSongBuffer = Buffer.from(writer.arrayBuffer);
+                               fs.writeFileSync(writePath, taggedSongBuffer);
+                               fs.remove(tempPath);
                        }
-               });
-               if (socket.currentItem && (socket.currentItem.id == id)) {
-                       exists = socket.currentItem.queueId;
                }
-               return exists;
+               logger.info(`[${track.artist.name} - ${track.title}] Downloaded`)
        }
-});
+})
 
 // Helper functions
 
@@ -1429,8 +1780,11 @@ function updateSettingsFile(config, value) {
 }
 
 function fixName (txt) {
+       txt = txt+""
   const regEx = /[\0\/\\:*?"<>|]/g;
-  return txt.replace(regEx, '_');
+  txt = txt.replace(regEx, '_');
+  txt = txt.slice(0,200);
+  return txt;
 }
 
 function antiDot(str){
@@ -1440,7 +1794,7 @@ function antiDot(str){
        if(str.length < 1){
                str = "dot";
        }
-       return fixName(str);
+       return str;
 }
 
 /**
@@ -1449,35 +1803,42 @@ function antiDot(str){
 function initFolders() {
        // Check if main folder exists
        if (!fs.existsSync(mainFolder)) {
-               mainFolder = defaultDownloadDir;
-               updateSettingsFile('downloadLocation', defaultDownloadDir);
+               mainFolder = defaultDownloadFolder;
+               updateSettingsFile('downloadLocation', defaultDownloadFolder);
        }
        //fs.removeSync(coverArtFolder);
-       fs.ensureDirSync(coverArtFolder);
+       //fs.ensureFolderSync(coverArtFolder);
 }
 
 /**
  * Creates the name of the tracks replacing wildcards to correct metadata
- * @param metadata
+ * @param track
  * @param filename
  * @param playlist
  * @returns {XML|string|*}
  */
-function settingsRegex(metadata, filename, playlist) {
-       filename = filename.replace(/%title%/g, metadata.title);
-       filename = filename.replace(/%album%/g, metadata.album);
-       filename = filename.replace(/%artist%/g, metadata.artist);
-       filename = filename.replace(/%year%/g, metadata.year);
-       if(typeof metadata.trackNumber != 'undefined'){
-               if(configFile.userDefined.padtrck){
-                        filename = filename.replace(/%number%/g, pad(splitNumber(metadata.trackNumber, false), splitNumber(metadata.trackNumber, true)));
-               }else{
-                       filename = filename.replace(/%number%/g, splitNumber(metadata.trackNumber, false));
+function settingsRegex(track, filename, playlist, saveFullArtists, paddingSize) {
+       try{
+               filename = filename.replace(/%title%/g, fixName(track.title));
+               filename = filename.replace(/%album%/g, fixName(track.album.title));
+               filename = filename.replace(/%artist%/g, fixName((saveFullArtists ? track.artistsString : track.artist.name)));
+               filename = filename.replace(/%year%/g, fixName(track.date.year));
+               filename = filename.replace(/%label%/g, fixName(track.publisher));
+               if(typeof track.trackNumber != 'undefined'){
+                       if(configFile.userDefined.padtrck){
+                                filename = filename.replace(/%number%/g, fixName(pad(track.trackNumber, (parseInt(paddingSize)>0 ? parseInt(paddingSize) : track.trackTotal))));
+                       }else{
+                               filename = filename.replace(/%number%/g, fixName(track.trackNumber));
+                       }
+               } else {
+                       filename = filename.replace(/%number%/g, '');
                }
-       } else {
-               filename = filename.replace(/%number%/g, '');
+               filename = filename.replace(/%explicit%/g, fixName((track.explicit==="1" ? (filename.indexOf(/[^%]explicit/g)>-1 ? "" : "(Explicit Version)") : "")));
+               filename = filename.replace(/%label%/g, fixName(track.genre ? (Array.isArray(track.genre) ? track.genre[0] : track.genre) : "Unknown"));
+               return filename.trim();
+       }catch(e){
+               logger.error("settingsRegex failed: "+e)
        }
-       return filename;
 }
 
 /**
@@ -1486,16 +1847,39 @@ function settingsRegex(metadata, filename, playlist) {
  * @param foldername
  * @returns {XML|string|*}
  */
-function settingsRegexAlbum(foldername, artist, album, year, rtype) {
-       foldername = foldername.replace(/%album%/g, album);
-       foldername = foldername.replace(/%artist%/g, artist);
-       foldername = foldername.replace(/%year%/g, year);
-       foldername = foldername.replace(/%type%/g, rtype);
+function settingsRegexAlbum(foldername, artist, album, year, rtype, explicit, publisher, genres) {
+       try{
+               foldername = foldername.replace(/%album%/g, fixName(album))
+               foldername = foldername.replace(/%artist%/g, fixName(artist))
+               foldername = foldername.replace(/%year%/g, fixName(year))
+               if (rtype){
+                       foldername = foldername.replace(/%type%/g, fixName(rtype[0].toUpperCase() + rtype.substring(1)))
+               }else{
+                       foldername = foldername.replace(/%type%/g, "")
+               }
+               foldername = foldername.replace(/%label%/g, fixName(publisher))
+               foldername = foldername.replace(/%explicit%/g, fixName((explicit ? (foldername.indexOf(/[^%]explicit/g)>-1 ? "" : "(Explicit)") : "")))
+               foldername = foldername.replace(/%genre%/g, fixName(genres ? (Array.isArray(genres) ? genres[0] : genres) : "Unknown"))
+               return foldername.trim();
+       }catch(e){
+               logger.error("settingsRegexAlbum failed: "+e)
+       }
+
+}
+
+function settingsRegexCover(foldername, artist, name) {
+       foldername = foldername.replace(/%name%/g, fixName(name));
+       foldername = foldername.replace(/%artist%/g, fixName(artist));
+       return foldername;
+}
+
+function settingsRegexArtistCover(foldername, artist) {
+       foldername = foldername.replace(/%artist%/g, fixName(artist));
        return foldername;
 }
 
 /**
- * I really don't understand what this does ... but it does something
+ * Pad number with 0s so max and str have the same nuber of characters
  * @param str
  * @param max
  * @returns {String|string|*}
@@ -1524,195 +1908,51 @@ function splitNumber(str,total){
        return i > 0 ? str.slice(0, i) : str;
 }
 
-function slimDownTrackInfo(trackOld){
-       let track = {};
-       track['SNG_ID'] = trackOld["SNG_ID"]
-       track['ARTISTS'] = trackOld["ARTISTS"]
-       track["ALB_ID"] = trackOld["ALB_ID"]
-       track["ALB_PICTURE"] = trackOld["ALB_PICTURE"]
-       track["ALB_TITLE"] = trackOld["ALB_TITLE"]
-       track["ART_NAME"] = trackOld["ART_NAME"]
-       track["BPM"] = trackOld["BPM"]
-       track["COPYRIGHT"] = trackOld["COPYRIGHT"]
-       track["DISK_NUMBER"] = trackOld["DISK_NUMBER"]
-       track["DURATION"] = trackOld["DURATION"]
-       track["EXPLICIT_LYRICS"] = trackOld["EXPLICIT_LYRICS"]
-       track["GAIN"] = trackOld["GAIN"]
-       track["ISRC"] = trackOld["ISRC"]
-       track["LYRICS_SYNC_JSON"] = trackOld["LYRICS_SYNC_JSON"]
-       track["LYRICS_TEXT"] = trackOld["LYRICS_TEXT"]
-       track["PHYSICAL_RELEASE_DATE"] = trackOld["PHYSICAL_RELEASE_DATE"]
-       track["SNG_CONTRIBUTORS"] = trackOld["SNG_CONTRIBUTORS"]
-       track["SNG_TITLE"] = trackOld["SNG_TITLE"]
-       track["TRACK_NUMBER"] = trackOld["TRACK_NUMBER"]
-       track["VERSION"] = trackOld["VERSION"]
-       track["FILESIZE_FLAC"] = trackOld["FILESIZE_FLAC"]
-       track["FILESIZE_MP3_320"] = trackOld["FILESIZE_MP3_320"]
-       track["FILESIZE_MP3_256"] = trackOld["FILESIZE_MP3_256"]
-       track["FILESIZE_MP3_128"] = trackOld["FILESIZE_MP3_128"]
-       track["FALLBACK"] = trackOld["FALLBACK"]
-       track.downloadUrl = trackOld.downloadUrl
-       track.format = trackOld.format
-       return track
+function swichReleaseType(id){
+       switch (id) {
+               case "0":
+                       return "Album";
+               case "1":
+                       return "Single";
+               case "3":
+                       return "EP";
+               default:
+                       return id;
+       }
 }
 
-function slimDownAlbumInfo(ajsonOld){
-       let ajson = {};
-       ajson.artist = {}
-       ajson.artist.name = ajsonOld.artist.name
-       ajson.nb_tracks = ajsonOld.nb_tracks
-       ajson.upc = ajsonOld.upc
-       ajson.record_type = ajsonOld.record_type
-       ajson.label = ajsonOld.label
-       ajson.genres = ajsonOld.genres
-       ajson.release_date = ajsonOld.release_date
-       ajson.tracks = {
-               data: ajsonOld.tracks.data.map(x=>{
-                       return {id: x.id};
+function uniqueArray(origin, destination, removeDupes=true){
+       Array.from(new Set(origin)).forEach(function(x){
+               if(destination.indexOf(x) == -1)
+                       destination.push(x);
+       });
+       if (removeDupes){
+               destination.forEach((name,index)=>{
+                       destination.forEach((name2,index2)=>{
+                               if(!(index===index2) && (name.indexOf(name2)!== -1)){
+                                       destination.splice(index, 1);
+                               }
+                       })
                })
        }
-       ajson.tracks.total = ajsonOld.tracks.total
-       return ajson
 }
 
-function parseMetadata(track, ajson, totalDiskNumber, settings, position, altmetadata){
-       let metadata;
-       if (track["VERSION"]) track["SNG_TITLE"] += " " + track["VERSION"];
-       if(altmetadata){
-               metadata = altmetadata;
-               if(track["LYRICS_TEXT"] && !metadata.unsynchronisedLyrics){
-                       metadata.unsynchronisedLyrics = {
-                               description: "",
-                               lyrics: track["LYRICS_TEXT"]
-                       };
-               }
-       }else{
-               metadata = {
-                       title: track["SNG_TITLE"],
-                       artist: track["ART_NAME"],
-                       album: track["ALB_TITLE"],
-                       performerInfo: ajson.artist.name,
-                       trackNumber: track["TRACK_NUMBER"] + "/" + ajson.nb_tracks,
-                       partOfSet: track["DISK_NUMBER"],
-                       explicit: track["EXPLICIT_LYRICS"],
-                       ISRC: track["ISRC"],
-               };
-               if (settings.extendedTags){
-                       metadata.length = track["DURATION"];
-                       metadata.BARCODE = ajson.upc;
-                       metadata.rtype = ajson.record_type;
-                       if(track["COPYRIGHT"]){
-                               metadata.copyright = track["COPYRIGHT"];
-                       }
-                       if(track["SNG_CONTRIBUTORS"]){
-                               if(track["SNG_CONTRIBUTORS"].composer){
-                                       let composertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].composer.length; i++) {
-                                               composertag += track["SNG_CONTRIBUTORS"].composer[i] + ", ";
-                                       }
-                                       metadata.composer = composertag.substring(0,composertag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].musicpublisher){
-                                       let publishertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].musicpublisher.length; i++) {
-                                               publishertag += track["SNG_CONTRIBUTORS"].musicpublisher[i] + ", ";
-                                       }
-                                       metadata.publisher = publishertag.substring(0,publishertag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].producer){
-                                       let producertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].producer.length; i++) {
-                                               producertag += track["SNG_CONTRIBUTORS"].producer[i] + ", ";
-                                       }
-                                       metadata.producer = producertag.substring(0,producertag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].engineer){
-                                       let engineertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].engineer.length; i++) {
-                                               engineertag += track["SNG_CONTRIBUTORS"].engineer[i] + ", ";
-                                       }
-                                       metadata.engineer = engineertag.substring(0,engineertag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].writer){
-                                       let writertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].writer.length; i++) {
-                                               writertag += track["SNG_CONTRIBUTORS"].writer[i] + ", ";
-                                       }
-                                       metadata.writer = writertag.substring(0,writertag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].author){
-                                       let authortag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].author.length; i++) {
-                                               authortag += track["SNG_CONTRIBUTORS"].author[i] + ", ";
-                                       }
-                                       metadata.author = authortag.substring(0,authortag.length-2);
-                               }
-                               if(track["SNG_CONTRIBUTORS"].mixer){
-                                       let mixertag = "";
-                                       for (let i = 0; i < track["SNG_CONTRIBUTORS"].mixer.length; i++) {
-                                               mixertag += track["SNG_CONTRIBUTORS"].mixer[i] + ", ";
-                                       }
-                                       metadata.mixer = mixertag.substring(0,mixertag.length-2);
-                               }
-                       }
-                       if(track["LYRICS_TEXT"]){
-                               metadata.unsynchronisedLyrics = {
-                                       description: "",
-                                       lyrics: track["LYRICS_TEXT"]
-                               };
-                       }
-                       if (track["GAIN"]) {
-                               metadata.trackgain = track["GAIN"];
-                       }
-               }
-               if(ajson.label && !metadata.publisher){
-                       metadata.publisher = ajson.label;
-               }
-               if (0 < parseInt(track["BPM"])) {
-                       metadata.bpm = track["BPM"];
-               }
-               if(ajson.genres && ajson.genres.data[0] && ajson.genres.data[0].name){
-                       metadata.genre = [];
-                       genreArray = [];
-                       ajson.genres.data.forEach(function(genre){
-                               genreArray.push(genre.name);
-                       });
-                       Array.from(new Set(genreArray)).forEach(function(genre){
-                               if(metadata.genre.indexOf(genre) == -1)
-                                       metadata.genre.push(genre);
-                       });
-                       let separator = settings.multitagSeparator;
-                       if (separator == "null") separator = String.fromCharCode(parseInt("\u0000",16))
-                       if (track.format != 9) metadata.genre = metadata.genre.join(separator);
-               }
-               if (track["ALB_PICTURE"]) {
-                       metadata.image = Deezer.albumPicturesHost + track["ALB_PICTURE"] + settings.artworkSize;
-               }
-               if(track["PHYSICAL_RELEASE_DATE"]){
-                       metadata.year = track["PHYSICAL_RELEASE_DATE"].slice(0, 4);
-               }else if (ajson.release_date) {
-                       metadata.year = ajson.release_date.slice(0, 4);
-               }
-               if(settings.plName && !(settings.createArtistFolder || settings.createAlbumFolder) && !settings.numplaylistbyalbum){
-                       metadata.trackNumber = (position+1).toString() + "/" + settings.playlist.fullSize;
-                       metadata.partOfSet = "1/1";
-               }
-               if (totalDiskNumber){
-                       metadata.partOfSet += "/"+totalDiskNumber
-               }
-       }
-       return metadata;
+async function asyncForEach(array, callback) {
+  for (let index = 0; index < array.length; index++) {
+    await callback(array[index], index, array);
+  }
 }
 
-process.on('unhandledRejection', function (err) {
-       logger.error(err.stack);
-});
 // Show crash error in console for debugging
+process.on('unhandledRejection', function (err) {
+       if (err) logger.error(err.stack ? err.stack : err)
+
+})
 process.on('uncaughtException', function (err) {
-       logger.error(err.stack);
-});
+       if (err) logger.error(err.stack ? err.stack : err)
+})
 
 // Exporting vars
-module.exports.mainFolder = mainFolder;
-module.exports.defaultSettings = defaultSettings;
-module.exports.defaultDownloadDir = defaultDownloadDir;
+module.exports.mainFolder = mainFolder
+module.exports.defaultSettings = defaultSettings
+module.exports.defaultDownloadFolder = defaultDownloadFolder