deemixer/server/dist/main.js

278 lines
13 KiB
JavaScript
Raw Normal View History

2021-05-23 20:42:02 +00:00
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
2021-06-05 11:58:50 +00:00
exports.restoreQueueFromDisk = exports.clearCompletedDownloads = exports.cancelAllDownloads = exports.cancelDownload = exports.startQueue = exports.addToQueue = exports.getQueue = exports.saveSettings = exports.getSettings = exports.listener = exports.plugins = exports.getArlFromAccessToken = exports.getAccessToken = exports.sessionDZ = exports.configFolder = exports.defaultSettings = void 0;
2021-05-23 20:42:02 +00:00
const fs_1 = __importDefault(require("fs"));
const path_1 = require("path");
const uuid_1 = require("uuid");
// @ts-expect-error
const deemix_1 = __importDefault(require("deemix"));
const ws_1 = __importDefault(require("ws"));
const app_1 = require("./app");
const errors_1 = require("./helpers/errors");
const Downloader = deemix_1.default.downloader.Downloader;
const { Single, Collection, Convertable } = deemix_1.default.types.downloadObjects;
exports.defaultSettings = deemix_1.default.settings.DEFAULTS;
exports.configFolder = deemix_1.default.utils.localpaths.getConfigFolder();
exports.sessionDZ = {};
2021-06-05 11:58:50 +00:00
let settings = deemix_1.default.settings.load(exports.configFolder);
2021-05-23 20:42:02 +00:00
exports.getAccessToken = deemix_1.default.utils.deezer.getAccessToken;
exports.getArlFromAccessToken = deemix_1.default.utils.deezer.getArlFromAccessToken;
2021-05-29 10:06:26 +00:00
exports.plugins = {
2021-06-05 11:58:50 +00:00
// eslint-disable-next-line new-cap
2021-05-29 10:06:26 +00:00
spotify: new deemix_1.default.plugins.spotify()
};
exports.plugins.spotify.setup();
2021-05-23 20:42:02 +00:00
exports.listener = {
send(key, data) {
if (data)
console.log(key, data);
else
console.log(key);
2021-06-05 11:58:50 +00:00
if (['downloadInfo', 'downloadWarn'].includes(key))
return;
2021-05-23 20:42:02 +00:00
app_1.wss.clients.forEach(client => {
if (client.readyState === ws_1.default.OPEN) {
client.send(JSON.stringify({ key, data }));
}
});
}
};
2021-05-29 10:06:26 +00:00
function getSettings() {
2021-06-08 17:56:53 +00:00
return { settings, defaultSettings: exports.defaultSettings, spotifySettings: exports.plugins.spotify.getSettings() };
2021-05-29 10:06:26 +00:00
}
exports.getSettings = getSettings;
function saveSettings(newSettings, newSpotifySettings) {
2021-05-23 20:42:02 +00:00
deemix_1.default.settings.save(newSettings, exports.configFolder);
2021-06-05 11:58:50 +00:00
settings = newSettings;
2021-06-08 17:56:53 +00:00
exports.plugins.spotify.saveSettings(newSpotifySettings);
2021-05-23 20:42:02 +00:00
}
exports.saveSettings = saveSettings;
2021-06-05 11:58:50 +00:00
let queueOrder = [];
const queue = {};
let currentJob = null;
2021-05-23 20:42:02 +00:00
restoreQueueFromDisk();
2021-06-05 11:58:50 +00:00
function getQueue() {
const result = {
queue,
queueOrder
};
if (currentJob && currentJob !== true) {
result.current = currentJob.downloadObject.getSlimmedDict();
}
return result;
}
exports.getQueue = getQueue;
2021-05-23 20:42:02 +00:00
function addToQueue(dz, url, bitrate) {
return __awaiter(this, void 0, void 0, function* () {
if (!dz.logged_in)
throw new errors_1.NotLoggedIn();
let downloadObjs = [];
const downloadErrors = [];
2021-06-05 11:58:50 +00:00
let link = '';
2021-05-23 20:42:02 +00:00
const requestUUID = uuid_1.v4();
if (url.length > 1) {
2021-06-05 11:58:50 +00:00
exports.listener.send('startGeneratingItems', { uuid: requestUUID, total: url.length });
2021-05-23 20:42:02 +00:00
}
for (let i = 0; i < url.length; i++) {
link = url[i];
console.log(`Adding ${link} to queue`);
let downloadObj;
try {
downloadObj = yield deemix_1.default.generateDownloadObject(dz, link, bitrate, exports.plugins, exports.listener);
}
catch (e) {
downloadErrors.push(e);
}
2021-05-23 20:42:02 +00:00
if (Array.isArray(downloadObj)) {
2021-05-29 14:21:00 +00:00
downloadObjs = downloadObjs.concat(downloadObj);
2021-05-23 20:42:02 +00:00
}
else if (downloadObj)
2021-05-23 20:42:02 +00:00
downloadObjs.push(downloadObj);
}
if (downloadErrors.length) {
downloadErrors.forEach((e) => {
if (!e.errid)
console.trace(e);
exports.listener.send('queueError', { link: e.link, error: e.message, errid: e.errid });
});
2021-05-23 20:42:02 +00:00
}
if (url.length > 1) {
2021-06-05 11:58:50 +00:00
exports.listener.send('finishGeneratingItems', { uuid: requestUUID, total: downloadObjs.length });
2021-05-23 20:42:02 +00:00
}
const slimmedObjects = [];
downloadObjs.forEach((downloadObj, pos) => {
2021-05-23 20:42:02 +00:00
// Check if element is already in queue
2021-06-05 11:58:50 +00:00
if (Object.keys(queue).includes(downloadObj.uuid)) {
2021-05-29 14:21:00 +00:00
exports.listener.send('alreadyInQueue', downloadObj.getEssentialDict());
delete downloadObjs[pos];
2021-05-29 14:21:00 +00:00
return;
}
2021-05-23 20:42:02 +00:00
// Save queue status when adding something to the queue
if (!fs_1.default.existsSync(exports.configFolder + 'queue'))
fs_1.default.mkdirSync(exports.configFolder + 'queue');
2021-06-05 11:58:50 +00:00
queueOrder.push(downloadObj.uuid);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
queue[downloadObj.uuid] = downloadObj.getEssentialDict();
queue[downloadObj.uuid].status = 'inQueue';
2021-05-23 20:42:02 +00:00
const savedObject = downloadObj.toDict();
savedObject.status = 'inQueue';
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${downloadObj.uuid}.json`, JSON.stringify(savedObject));
slimmedObjects.push(downloadObj.getSlimmedDict());
});
2021-06-05 11:58:50 +00:00
const isSingleObject = downloadObjs.length === 1;
2021-05-23 20:42:02 +00:00
if (isSingleObject)
exports.listener.send('addedToQueue', downloadObjs[0].getSlimmedDict());
else
exports.listener.send('addedToQueue', slimmedObjects);
startQueue(dz);
return slimmedObjects;
});
}
exports.addToQueue = addToQueue;
function startQueue(dz) {
return __awaiter(this, void 0, void 0, function* () {
do {
2021-06-05 11:58:50 +00:00
if (currentJob !== null || queueOrder.length === 0) {
2021-05-23 20:42:02 +00:00
// Should not start another download
return null;
}
2021-06-05 11:58:50 +00:00
currentJob = true; // lock currentJob
const currentUUID = queueOrder.shift() || '';
2021-05-23 20:42:02 +00:00
console.log(currentUUID);
2021-06-05 11:58:50 +00:00
queue[currentUUID].status = 'downloading';
2021-05-23 20:42:02 +00:00
const currentItem = JSON.parse(fs_1.default.readFileSync(exports.configFolder + `queue${path_1.sep}${currentUUID}.json`).toString());
let downloadObject;
switch (currentItem.__type__) {
case 'Single':
downloadObject = new Single(currentItem);
break;
case 'Collection':
downloadObject = new Collection(currentItem);
break;
case 'Convertable':
downloadObject = new Convertable(currentItem);
2021-06-05 11:58:50 +00:00
downloadObject = yield exports.plugins[downloadObject.plugin].convert(dz, downloadObject, settings, exports.listener);
2021-05-29 10:06:26 +00:00
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`, JSON.stringify(Object.assign(Object.assign({}, downloadObject.toDict()), { status: 'inQueue' })));
2021-05-23 20:42:02 +00:00
break;
}
2021-06-05 11:58:50 +00:00
currentJob = new Downloader(dz, downloadObject, settings, exports.listener);
2021-05-23 20:42:02 +00:00
exports.listener.send('startDownload', currentUUID);
2021-06-05 11:58:50 +00:00
yield currentJob.start();
2021-05-23 20:42:02 +00:00
if (!downloadObject.isCanceled) {
// Set status
2021-06-05 11:58:50 +00:00
if (downloadObject.failed === downloadObject.size) {
queue[currentUUID].status = 'failed';
2021-05-23 20:42:02 +00:00
}
else if (downloadObject.failed > 0) {
2021-06-05 11:58:50 +00:00
queue[currentUUID].status = 'withErrors';
2021-05-23 20:42:02 +00:00
}
else {
2021-06-05 11:58:50 +00:00
queue[currentUUID].status = 'completed';
2021-05-23 20:42:02 +00:00
}
const savedObject = downloadObject.getSlimmedDict();
2021-06-05 11:58:50 +00:00
savedObject.status = queue[currentUUID].status;
2021-05-23 20:42:02 +00:00
// Save queue status
2021-06-05 11:58:50 +00:00
queue[currentUUID] = savedObject;
2021-05-23 20:42:02 +00:00
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${currentUUID}.json`, JSON.stringify(savedObject));
}
2021-06-05 11:58:50 +00:00
console.log(queueOrder);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
currentJob = null;
} while (queueOrder.length);
2021-05-23 20:42:02 +00:00
});
}
exports.startQueue = startQueue;
function cancelDownload(uuid) {
2021-06-05 11:58:50 +00:00
if (Object.keys(queue).includes(uuid)) {
switch (queue[uuid].status) {
2021-05-23 20:42:02 +00:00
case 'downloading':
2021-06-05 11:58:50 +00:00
currentJob.downloadObject.isCanceled = true;
2021-05-23 20:42:02 +00:00
exports.listener.send('cancellingCurrentItem', uuid);
break;
case 'inQueue':
2021-06-05 11:58:50 +00:00
queueOrder.splice(queueOrder.indexOf(uuid), 1);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
2021-05-23 20:42:02 +00:00
// break
2021-06-05 11:58:50 +00:00
// eslint-disable-next-line no-fallthrough
2021-05-23 20:42:02 +00:00
default:
// This gets called even in the 'inQueue' case. Is this the expected behaviour? If no, de-comment the break
exports.listener.send('removedFromQueue', uuid);
break;
}
fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${uuid}.json`);
2021-06-05 11:58:50 +00:00
delete queue[uuid];
2021-05-23 20:42:02 +00:00
}
}
exports.cancelDownload = cancelDownload;
function cancelAllDownloads() {
2021-06-05 11:58:50 +00:00
queueOrder = [];
2021-05-23 20:42:02 +00:00
let currentItem = null;
2021-06-05 11:58:50 +00:00
Object.values(queue).forEach((downloadObject) => {
if (downloadObject.status === 'downloading') {
currentJob.downloadObject.isCanceled = true;
2021-05-23 20:42:02 +00:00
exports.listener.send('cancellingCurrentItem', downloadObject.uuid);
currentItem = downloadObject.uuid;
}
fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`);
2021-06-05 11:58:50 +00:00
delete queue[downloadObject.uuid];
2021-05-23 20:42:02 +00:00
});
2021-06-05 11:58:50 +00:00
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
2021-05-23 20:42:02 +00:00
exports.listener.send('removedAllDownloads', currentItem);
}
exports.cancelAllDownloads = cancelAllDownloads;
function clearCompletedDownloads() {
2021-06-05 11:58:50 +00:00
Object.values(queue).forEach((downloadObject) => {
2021-05-23 20:42:02 +00:00
if (downloadObject.status === 'completed') {
fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`);
2021-06-05 11:58:50 +00:00
delete queue[downloadObject.uuid];
2021-05-23 20:42:02 +00:00
}
});
exports.listener.send('removedFinishedDownloads');
}
exports.clearCompletedDownloads = clearCompletedDownloads;
function restoreQueueFromDisk() {
if (!fs_1.default.existsSync(exports.configFolder + 'queue'))
fs_1.default.mkdirSync(exports.configFolder + 'queue');
const allItems = fs_1.default.readdirSync(exports.configFolder + 'queue');
allItems.forEach((filename) => {
2021-06-05 11:58:50 +00:00
if (filename === 'order.json') {
queueOrder = JSON.parse(fs_1.default.readFileSync(exports.configFolder + `queue${path_1.sep}order.json`).toString());
2021-05-23 20:42:02 +00:00
}
else {
const currentItem = JSON.parse(fs_1.default.readFileSync(exports.configFolder + `queue${path_1.sep}${filename}`).toString());
if (currentItem.status === 'inQueue') {
let downloadObject;
switch (currentItem.__type__) {
case 'Single':
downloadObject = new Single(currentItem);
break;
case 'Collection':
downloadObject = new Collection(currentItem);
break;
case 'Convertable':
downloadObject = new Convertable(currentItem);
break;
}
2021-06-05 11:58:50 +00:00
queue[downloadObject.uuid] = downloadObject.getEssentialDict();
queue[downloadObject.uuid].status = 'inQueue';
2021-05-23 20:42:02 +00:00
}
else {
2021-06-05 11:58:50 +00:00
queue[currentItem.uuid] = currentItem;
2021-05-23 20:42:02 +00:00
}
}
});
}
exports.restoreQueueFromDisk = restoreQueueFromDisk;