Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
* _____ _ _
* | __ \ | | | |
* | | | | ___ ___ ____| | ___ __ _ __| | ___ _ __
* | | | | / _ \ / _ \|_ /| | / _ \ / _` | / _` | / _ \| '__|
* | |__| || __/| __/ / / | || (_) || (_| || (_| || __/| |
* |_____/ \___| \___|/___||_| \___/ \__,_| \__,_| \___||_|
*
*
*
* Maintained by ExtendLord <https://www.reddit.com/user/ExtendLord/>
* Original work by ZzMTV <https://boerse.to/members/zzmtv.3378614/>
* */
if(!fs.existsSync(userdata+"config.json")){
fs.outputFileSync(userdata+"config.json",fs.readFileSync(__dirname+path.sep+"defaul
t.json",'utf8'));
}
// 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 = {
"trackNameTemplate": "%artist% - %title%",
"playlistTrackNameTemplate": "%number% - %artist% - %title%",
"albumNameTemplate": "%artist% - %album%",
"createM3UFile": false,
"createArtistFolder": false,
"createAlbumFolder": false,
"downloadLocation": null,
"artworkSize": "/1400x1400.jpg",
"hifi": false,
"padtrck": false,
"syncedlyrics": false,
"numplaylistbyalbum": false
};
if (configFile.userDefined.downloadLocation != null) {
mainFolder = configFile.userDefined.downloadLocation;
}
initFolders();
// END
//Autologin encryption/decryption
function alencrypt(input) {
var iv = crypto.randomBytes(16);
var encrypted;
function aldecrypt(encoded) {
var combined = new Buffer(encoded, 'hex');
// Create iv
var iv = new Buffer(16);
combined.copy(iv, 0, 0, 16);
edata = combined.slice(16).toString('binary');
// Decipher encrypted data
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
return plaintext;
}
}catch(e){
Deezer.logs('Warning',"Invalid autologin file, deleting");
fs.unlink(autologinLocation,function(){
});
return;
}
fdata = fdata.split('\n');
socket.emit("autologin",fdata[0],fdata[1]);
});
});
socket.on("logout", function(){
Deezer.logs('Info',"Logged out");
fs.unlink(autologinLocation,function(){
});
return;
});
if(track.trackSocket.currentItem.type == "track"){
let complete;
if (!track.trackSocket.currentItem.percentage) {
track.trackSocket.currentItem.percentage = 0;
}
if(configFile.userDefined.hifi){
complete = track.FILESIZE_FLAC;
}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;
}
}
function addToQueue(object) {
socket.downloadQueue.push(object);
socket.emit('addToQueue', object);
queueDownload(getNextDownload());
}
function getNextDownload() {
if (socket.currentItem != null || socket.downloadQueue.length == 0) {
if (socket.downloadQueue.length == 0 && socket.currentItem ==
null) {
socket.emit("emptyDownloadQueue", {});
}
return null;
}
socket.currentItem = socket.downloadQueue[0];
return socket.currentItem;
}
if (downloading.type == "track") {
Deezer.logs('Info',"Registered a track "+downloading.id);
downloadTrack([downloading.id,0], downloading.settings, null,
function (err) {
if (err) {
downloading.failed++;
} else {
downloading.downloaded++;
}
socket.emit("updateQueue", downloading);
if (socket.downloadQueue[0] &&
(socket.downloadQueue[0].queueId == downloading.queueId)) {
socket.downloadQueue.shift();
}
socket.currentItem = null;
//fs.rmdirSync(coverArtDir);
queueDownload(getNextDownload());
});
} else if (downloading.type == "playlist") {
Deezer.logs('Info',"Registered a playlist "+downloading.id);
Deezer.getPlaylistTracks(downloading.id, function (tracks, err) {
downloading.playlistContent = tracks.data.map((t) => {
if(t.FALLBACK){
if(t.FALLBACK.SNG_ID){
return [t.id,t.FALLBACK.SNG_ID];
}
}
return [t.id,0];
});
downloading.settings.plName = downloading.name;
async.eachSeries(downloading.playlistContent, function (id,
callback) {
if (downloading.cancelFlag) {
Deezer.logs('Info',"Stopping the playlist
queue");
callback("stop");
return;
}
downloading.settings.playlist = {
position:
downloading.playlistContent.indexOf(id),
fullSize: downloading.playlistContent.length
};
downloadTrack(id, downloading.settings, null,
function (err) {
if (!err) {
downloading.downloaded++;
} else {
downloading.failed++;
}
socket.emit("updateQueue", downloading);
callback();
});
}, function (err) {
Deezer.logs('Info',"Playlist finished
"+downloading.name);
if(typeof socket.downloadQueue[0] != 'undefined'){
socket.emit("downloadProgress", {
queueId: socket.downloadQueue[0].queueId,
percentage: 100
});
}
if (downloading && socket.downloadQueue[0] &&
socket.downloadQueue[0].queueId == downloading.queueId)
socket.downloadQueue.shift();
socket.currentItem = null;
//fs.rmdirSync(coverArtDir);
queueDownload(getNextDownload());
});
});
} else if (downloading.type == "album") {
Deezer.logs('Info',"Registered an album "+downloading.id);
Deezer.getAlbumTracks(downloading.id, function (tracks, err) {
downloading.playlistContent = tracks.data.map((t) => {
if(t.FALLBACK){
if(t.FALLBACK.SNG_ID){
return [t.id,t.FALLBACK.SNG_ID];
}
}
return [t.id,0];
});
downloading.settings.tagPosition = true;
downloading.settings.albName = downloading.name;
downloading.settings.artName = downloading.artist;
async.eachSeries(downloading.playlistContent, function (id,
callback) {
if (downloading.cancelFlag) {
Deezer.logs('Info',"Stopping the album queue");
callback("stop");
return;
}
downloading.settings.playlist = {
position:
downloading.playlistContent.indexOf(id),
fullSize: downloading.playlistContent.length
};
downloadTrack(id, downloading.settings, null,
function (err) {
if (!err) {
downloading.downloaded++;
} else {
downloading.failed++;
}
socket.emit("updateQueue", downloading);
callback();
});
}, function (err) {
if (downloading.countPerAlbum) {
if (socket.downloadQueue.length > 1 &&
socket.downloadQueue[1].queueId == downloading.queueId) {
socket.downloadQueue[1].download =
downloading.downloaded;
}
socket.emit("updateQueue", downloading);
}
Deezer.logs('Info',"Album finished
"+downloading.name);
if(typeof socket.downloadQueue[0] != 'undefined'){
socket.emit("downloadProgress", {
queueId: socket.downloadQueue[0].queueId,
percentage: 100
});
}
if (downloading && socket.downloadQueue[0] &&
socket.downloadQueue[0].queueId == downloading.queueId)
socket.downloadQueue.shift();
socket.currentItem = null;
queueDownload(getNextDownload());
});
});
}
}
socket.on("getChartsTopCountry", function () {
Deezer.getChartsTopCountry(function (charts, err) {
if(err){
return;
}
if(charts){
charts = charts.data || [];
}else{
charts = [];
}
socket.emit("getChartsTopCountry", {charts: charts.data, err:
err});
});
});
if (countries.indexOf(data.country) == -1) {
socket.emit("getChartsTrackListByCountry", {err: "Country
not found"});
return;
}
if (data.type == 'artist') {
Deezer.getArtistAlbums(data.id, function (response, err) {
if (err) {
socket.emit("getTrackList", {err: "wrong id",
response: {}, id: data.id, reqType: data.type});
return;
}
socket.emit("getTrackList", {response: response, id:
data.id, reqType: data.type});
});
} else {
let reqType = data.type.charAt(0).toUpperCase() +
data.type.slice(1);
});
socket.on("getUserSettings", function () {
let settings = configFile.userDefined;
if (!settings.downloadLocation) {
settings.downloadLocation = mainFolder;
}
configFile.userDefined = settings.userDefined;
fs.outputFile(configFileLocation, JSON.stringify(configFile, null, 2),
function (err) {
if (err) return;
Deezer.logs('Info',"Settings updated");
initFolders();
});
});
if (track["ALB_PICTURE"]) {
metadata.image = Deezer.albumPicturesHost
+ track["ALB_PICTURE"] + settings.artworkSize;
}
if (ajson.release_date) {
metadata.year =
ajson.release_date.slice(0, 4);
metadata.date = ajson.release_date;
}else if(track["PHYSICAL_RELEASE_DATE"]){
metadata.year =
track["PHYSICAL_RELEASE_DATE"].slice(0, 4);
metadata.date =
track["PHYSICAL_RELEASE_DATE"];
}
}
let filename = fixName(`${metadata.artist} - $
{metadata.title}`);
if (settings.filename) {
filename = fixName(settingsRegex(metadata,
settings.filename, settings.playlist));
}
if (settings.createAlbumFolder) {
if(settings.artName){
filepath +=
antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,settings.artName,se
ttings.albName))) + path.sep;
}else{
filepath +=
antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,metadata.performerI
nfo,metadata.album))) + path.sep;
}
}
} else if (settings.plName) {
filepath += antiDot(fixName(settings.plName)) +
path.sep;
} else if (settings.artName) {
filepath +=
antiDot(fixName(settingsRegexAlbum(metadata,settings.foldername,settings.artName,se
ttings.albName))) + path.sep;
}
let writePath;
if(track.format == 9){
writePath = filepath + filename + '.flac';
}else{
writePath = filepath + filename + '.mp3';
}
if(track["LYRICS_SYNC_JSON"] &&
configFile.userDefined.syncedlyrics){
var lyricsbuffer = "";
for(var
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";
}
}
if(track.format == 9){
fs.outputFile(writePath.substring(0,writePath.length-
5)+".lrc",lyricsbuffer,function(){});
}else{
fs.outputFile(writePath.substring(0,writePath.length-
4)+".lrc",lyricsbuffer,function(){});
}
}
Deezer.logs('Info','Downloading file to ' +
writePath);
if (fs.existsSync(writePath)) {
Deezer.logs('Info',"Already downloaded: " +
metadata.artist + ' - ' + metadata.title);
callback();
return;
}
//Get image
if (metadata.image) {
let imgPath;
//If its not from an album but a playlist.
if(!settings.tagPosition && !
settings.createAlbumFolder){
imgPath = coverArtFolder +
fixName(metadata.ISRC) + ".jpg";
}else{
imgPath = filepath + "folder.jpg";
}
if(fs.existsSync(imgPath) && !
imgPath.includes(coverArtFolder)){
metadata.imagePath =
(imgPath).replace(/\\/g, "/");
Deezer.logs('Info',"Starting the download
process CODE:1");
condownload();
}else{
request.get(metadata.image, {encoding:
'binary'}, function(error,response,body){
if(error){
Deezer.logs('Error',
error.stack);
metadata.image = undefined;
metadata.imagePath =
undefined;
return;
}
fs.outputFile(imgPath,body,'binary',function(err){
if(err){
Deezer.logs('Error',
err.stack);
metadata.image = undefined;
metadata.imagePath =
undefined;
return;
}
metadata.imagePath =
(imgPath).replace(/\\/g, "/");
Deezer.logs('Info',"Starting
the download process CODE:2");
condownload();
})
});
}
}else{
metadata.image = undefined;
Deezer.logs('Info',"Starting the download
process CODE:3");
condownload();
}
function condownload(){
var tempPath = writePath+".temp";
Deezer.logs('Info',"Downloading and
decrypting");
Deezer.decryptTrack(tempPath,track, function
(err) {
if (err && err.message == "aborted") {
socket.currentItem.cancelFlag =
true;
Deezer.logs('Info',"Track got
aborted");
callback();
return;
}
if (err) {
Deezer.hasTrackAlternative(id[0],
function (alternative, err) {
if (err || !alternative) {
if(metadata.artist.indexOf(artist['ART_NAME']) == -1)
metadata.artist += ', '
+ artist['ART_NAME'];
}
});
if(track.format == 9){
let flacComments = [
'TITLE=' + metadata.title,
'ALBUM=' + metadata.album,
'ALBUMARTIST=' +
metadata.performerInfo,
'ARTIST=' + metadata.artist,
'TRACKNUMBER=' +
splitNumber(metadata.trackNumber,false),
'DISCNUMBER=' +
splitNumber(metadata.partOfSet,false),
'TRACKTOTAL=' +
splitNumber(metadata.trackNumber,true),
'DISCTOTAL=' +
splitNumber(metadata.partOfSet,true),
'LENGTH=' + metadata.length,
'ISRC=' + metadata.ISRC,
'BARCODE=' +
metadata.BARCODE,
'ITUNESADVISORY=' +
metadata.explicit
];
if(metadata.unsynchronisedLyrics){
flacComments.push('LYRICS='+metadata.unsynchronisedLyrics.lyrics);
}
if(metadata.genre){
flacComments.push('GENRE=' +
metadata.genre);
}
if(metadata.copyright){
flacComments.push('COPYRIGHT=' + metadata.copyright);
}
if (0 < parseInt(metadata.year)) {
flacComments.push('DATE=' +
metadata.date);
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});
if (mdb.isLast) {
var res = 0;
if(configFile.userDefined.artworkSize.includes("1400")){
res = 1400;
}else
if(configFile.userDefined.artworkSize.includes("1200")){
res = 1200;
}else
if(configFile.userDefined.artworkSize.includes("1000")){
res = 1000;
}else
if(configFile.userDefined.artworkSize.includes("800")){
res = 800;
}else
if(configFile.userDefined.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',
metadata.trackNumber)
.setFrame('TPOS',
metadata.partOfSet)
.setFrame('TLEN',
metadata.length)
.setFrame('TSRC',
metadata.ISRC)
.setFrame('TXXX', {
description: 'BARCODE',
value: metadata.BARCODE
})
if(metadata.imagePath){
const coverBuffer =
fs.readFileSync(metadata.imagePath);
writer.setFrame('APIC', {
type: 3,
data: coverBuffer,
description: 'front
cover'
});
}
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('TDAT',
metadata.date);
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();
});
}
});
});
});
}
function checkIfAlreadyInQueue(id) {
let exists = false;
for (let i = 0; i < socket.downloadQueue.length; i++) {
if (socket.downloadQueue[i].id == id) {
exists = socket.downloadQueue[i].queueId;
}
}
if (socket.currentItem && (socket.currentItem.id == id)) {
exists = socket.currentItem.queueId;
}
return exists;
}
});
// Helper functions
/**
* Updates individual parameters in the settings file
* @param config
* @param value
*/
function updateSettingsFile(config, value) {
configFile.userDefined[config] = value;
function antiDot(str){
while(str[str.length-1] == "." || str[str.length-1] == " " || str[str.length-
1] == "\n"){
str = str.substring(0,str.length-1);
}
if(str.length < 1){
str = "dot";
}
return fixName(str);
}
/**
* Initialize the temp folder for covers and main folder for downloads
*/
function initFolders() {
// Check if main folder exists
if (!fs.existsSync(mainFolder)) {
mainFolder = defaultDownloadDir;
updateSettingsFile('downloadLocation', defaultDownloadDir);
}
fs.removeSync(coverArtFolder);
fs.ensureDirSync(coverArtFolder);
/**
* Creates the name of the tracks replacing wildcards to correct metadata
* @param metadata
* @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));
}
} else {
filename = filename.replace(/%number%/g, '');
}
return filename;
}
/**
* Creates the name of the albums folder replacing wildcards to correct metadata
* @param metadata
* @param foldername
* @returns {XML|string|*}
*/
function settingsRegexAlbum(metadata, foldername, artist, album) {
foldername = foldername.replace(/%album%/g, album);
foldername = foldername.replace(/%artist%/g, artist);
foldername = foldername.replace(/%year%/g, metadata.year);
foldername = foldername.replace(/%type%/g, metadata.rtype);
return foldername;
}
/**
* I really don't understand what this does ... but it does something
* @param str
* @param max
* @returns {String|string|*}
*/
function pad(str, max) {
str = str.toString();
max = max.toString();
return str.length < max.length || str.length == 1 ? pad("0" + str, max) :
str;
}
/**
* Splits the %number%
* @param string str
* @return string
*/
function splitNumber(str,total){
str = str.toString();
var i = str.indexOf("/");
if(total && i > 0){
return str.slice(i+1, str.length);
}else if(i > 0){
return str.slice(0, i);
}else{
return str;
}
return i > 0 ? str.slice(0, i) : str;
}
/**
* An interval that stops after a number of repetitions
* @param success
* @param delay
* @param repetitions
*/
function magicInterval(success, delay, repetitions) {
let x = 0;
let intervalID = setInterval(function () {
success(intervalID);
// Exporting vars
module.exports.mainFolder = mainFolder;
module.exports.defaultSettings = defaultSettings;
module.exports.defaultDownloadDir = defaultDownloadDir;