Merge branch 'lidarr' into 'main'

Webpack server and Lidarr support

See merge request RemixDev/deemix-gui!3
This commit is contained in:
RemixDev 2021-07-16 10:39:32 +00:00
commit ceaf5bd009
67 changed files with 7873 additions and 7123 deletions

View File

@ -10,6 +10,7 @@ const argv = yargs(hideBin(process.argv)).options({
host: { type: 'string', default: '127.0.0.1' },
dev: { type: 'boolean', default: false}
}).argv
const server = require('./server/dist/app.js')
const PORT = process.env.DEEMIX_PORT || argv.port
@ -23,7 +24,6 @@ const windowState = new WindowStateManager('mainWindow', {
})
function createWindow () {
require('./server/dist/app.js')
win = new BrowserWindow({
width: windowState.width,
height: windowState.height,
@ -91,7 +91,7 @@ app.on('window-all-closed', () => {
})
ipcMain.on('openDownloadsFolder', (event)=>{
const { downloadLocation } = require('./server/dist/main.js').getSettings().settings
const { downloadLocation } = server.getSettings().settings
shell.openPath(downloadLocation)
})

View File

@ -22,49 +22,11 @@
"devDependencies": {
"electron": "^12.0.9",
"electron-builder": "22.11.4",
"pkg": "5.3.0",
"@nuxtjs/eslint-config": "6.0.0",
"@types/cookie-parser": "1.4.2",
"@types/debug": "4.1.5",
"@types/express": "4.17.11",
"@types/express-session": "^1.17.3",
"@types/jest": "26.0.22",
"@types/morgan": "1.9.2",
"@types/node": "14.14.37",
"@types/ramda": "0.27.40",
"@types/supertest": "2.0.11",
"@types/uuid": "8.3.0",
"@types/ws": "7.4.1",
"@typescript-eslint/eslint-plugin": "4.21.0",
"@typescript-eslint/parser": "4.21.0",
"@types/yargs": "17.0.0",
"eslint": "7.23.0",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-prettier": "3.3.1",
"jest": "26.6.3",
"nodemon": "2.0.7",
"prettier": "2.2.1",
"supertest": "6.1.3",
"ts-jest": "26.5.4",
"ts-node": "9.1.1",
"ts-node-dev": "1.1.6",
"typescript": "4.2.4"
"pkg": "5.3.0"
},
"dependencies": {
"electron-context-menu": "^3.1.0",
"electron-window-state-manager": "^0.3.2",
"cookie-parser": "1.4.5",
"debug": "2.6.9",
"deemix": "3.0.3",
"deezer-js": "1.0.0",
"dotenv": "8.2.0",
"express": "4.17.1",
"express-session": "^1.17.1",
"morgan": "1.10.0",
"ramda": "0.27.1",
"uuid": "8.3.2",
"ws": "7.4.5",
"yargs": "17.0.1"
},
"build": {

60
server/dist/app.js vendored

File diff suppressed because one or more lines are too long

442
server/dist/app.js.LICENSE.txt vendored Normal file
View File

@ -0,0 +1,442 @@
/*!
* Copyright 2010 LearnBoost <dev@learnboost.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*!
* Connect - session - Cookie
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/*!
* Connect - session - Session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/*!
* Connect - session - Store
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/*!
* Copyright (c) 2015, Salesforce.com, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Salesforce.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*!
* Copyright (c) 2018, Salesforce.com, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Salesforce.com nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*!
* Prototype.
*/
/*!
* accepts
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* basic-auth
* Copyright(c) 2013 TJ Holowaychuk
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* body-parser
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* bytes
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015 Jed Watson
* MIT Licensed
*/
/*!
* content-disposition
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* content-type
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* cookie-parser
* Copyright(c) 2014 TJ Holowaychuk
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014-2018 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* destroy
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* ee-first
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* encodeurl
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* escape-html
* Copyright(c) 2012-2013 TJ Holowaychuk
* Copyright(c) 2015 Andreas Lubbe
* Copyright(c) 2015 Tiancheng "Timothy" Gu
* MIT Licensed
*/
/*!
* etag
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express-session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express-session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* finalhandler
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* forwarded
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* fresh
* Copyright(c) 2012 TJ Holowaychuk
* Copyright(c) 2016-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* http-errors
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* media-typer
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* memorystore
* Copyright(c) 2020 Rocco Musolino <@roccomuso>
* MIT Licensed
*/
/*!
* merge-descriptors
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* methods
* Copyright(c) 2013-2014 TJ Holowaychuk
* Copyright(c) 2015-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* mime-types
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* morgan
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* negotiator
* Copyright(c) 2012 Federico Romero
* Copyright(c) 2012-2014 Isaac Z. Schlueter
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* on-finished
* Copyright(c) 2013 Jonathan Ong
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* on-headers
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* parseurl
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* proxy-addr
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* random-bytes
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* range-parser
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* raw-body
* Copyright(c) 2013-2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* send
* Copyright(c) 2012 TJ Holowaychuk
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* serve-static
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* statuses
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* toidentifier
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* type-is
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* uid-safe
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* unpipe
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* vary
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/** @license URI.js v4.4.1 (c) 2011 Gary Court. License: http://github.com/garycourt/uri-js */

View File

@ -1,41 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NotLoggedIn = exports.AlreadyInQueue = exports.QueueError = exports.isBadRequestError = exports.BadRequestError = exports.consoleError = exports.consoleInfo = void 0;
const ramda_1 = require("ramda");
const prependDeemix = ramda_1.concat('[deemix-server]: ');
const consoleInfo = (infoText) => console.info(prependDeemix(infoText));
exports.consoleInfo = consoleInfo;
const consoleError = (errorText) => console.error(prependDeemix(errorText));
exports.consoleError = consoleError;
class BadRequestError extends Error {
constructor() {
super();
this.message = 'Bad request!';
}
}
exports.BadRequestError = BadRequestError;
const isBadRequestError = (error) => error instanceof BadRequestError;
exports.isBadRequestError = isBadRequestError;
class QueueError extends Error {
constructor(message) {
super(message);
this.name = 'QueueError';
}
}
exports.QueueError = QueueError;
class AlreadyInQueue extends QueueError {
constructor(dwObj, silent) {
super(`${dwObj.artist} - ${dwObj.title} is already in queue.`);
this.name = 'AlreadyInQueue';
this.item = dwObj;
this.silent = silent;
}
}
exports.AlreadyInQueue = AlreadyInQueue;
class NotLoggedIn extends QueueError {
constructor() {
super(`You must be logged in to start a download.`);
this.name = 'NotLoggedIn';
}
}
exports.NotLoggedIn = NotLoggedIn;

View File

@ -1,9 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WEBUI_DIR = exports.ROOT_DIR = void 0;
const path_1 = __importDefault(require("path"));
exports.ROOT_DIR = path_1.default.resolve(path_1.default.join(__dirname, '..', '..', '..'));
exports.WEBUI_DIR = path_1.default.join(exports.ROOT_DIR, 'webui', 'public');

View File

@ -1,21 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizePort = void 0;
/**
* Normalize a port into a number, string, or false.
*
* @since 0.0.0
*/
function normalizePort(portString) {
const port = parseInt(portString, 10);
if (isNaN(port)) {
// named pipe
return portString;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
exports.normalizePort = normalizePort;

View File

@ -1,5 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObjectEmpy = void 0;
const isObjectEmpy = (obj) => Object.keys(obj).length === 0;
exports.isObjectEmpy = isObjectEmpy;

View File

@ -1,47 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getListeningCb = exports.getErrorCb = void 0;
const errors_1 = require("./errors");
/**
* Event listener for HTTP server "error" event.
*
* @since 0.0.0
*/
function getErrorCb(port) {
return (error) => {
if (error.syscall !== 'listen') {
throw error;
}
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES': {
console.error(bind + ' requires elevated privileges');
process.exit(1);
}
case 'EADDRINUSE': {
console.error(bind + ' is already in use');
process.exit(1);
}
default:
throw error;
}
};
}
exports.getErrorCb = getErrorCb;
/**
* Event listener for HTTP server "listening" event.
*
* @since 0.0.0
*/
function getListeningCb(server, debug) {
return () => {
const addr = server.address();
if (addr) {
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debug(`Listening on ${bind}`);
errors_1.consoleInfo(`Listening on ${bind}`);
}
};
}
exports.getListeningCb = getListeningCb;

302
server/dist/main.js vendored
View File

@ -1,302 +0,0 @@
"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 });
exports.restoreQueueFromDisk = exports.clearCompletedDownloads = exports.cancelAllDownloads = exports.cancelDownload = exports.startQueue = exports.addToQueue = exports.getQueue = exports.saveSettings = exports.getSettings = exports.listener = exports.plugins = exports.isDeezerAvailable = exports.deemixVersion = exports.getArlFromAccessToken = exports.getAccessToken = exports.sessionDZ = exports.configFolder = exports.defaultSettings = void 0;
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 got_1 = __importDefault(require("got"));
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 = {};
let settings = deemix_1.default.settings.load(exports.configFolder);
exports.getAccessToken = deemix_1.default.utils.deezer.getAccessToken;
exports.getArlFromAccessToken = deemix_1.default.utils.deezer.getArlFromAccessToken;
exports.deemixVersion = require('../../node_modules/deemix/package.json').version;
let deezerAvailable = null;
function isDeezerAvailable() {
return __awaiter(this, void 0, void 0, function* () {
if (deezerAvailable === null) {
let response;
try {
response = yield got_1.default.get('https://www.deezer.com/', {
headers: { Cookie: 'dz_lang=en; Domain=deezer.com; Path=/; Secure; hostOnly=false;' },
retry: 5
});
}
catch (e) {
console.trace(e);
deezerAvailable = false;
return deezerAvailable;
}
const title = (response.body.match(/<title[^>]*>([^<]+)<\/title>/)[1] || '').trim();
deezerAvailable = title !== 'Deezer will soon be available in your country.';
}
return deezerAvailable;
});
}
exports.isDeezerAvailable = isDeezerAvailable;
exports.plugins = {
// eslint-disable-next-line new-cap
spotify: new deemix_1.default.plugins.spotify()
};
exports.plugins.spotify.setup();
exports.listener = {
send(key, data) {
if (data)
console.log(key, data);
else
console.log(key);
if (['downloadInfo', 'downloadWarn'].includes(key))
return;
app_1.wss.clients.forEach(client => {
if (client.readyState === ws_1.default.OPEN) {
client.send(JSON.stringify({ key, data }));
}
});
}
};
function getSettings() {
return { settings, defaultSettings: exports.defaultSettings, spotifySettings: exports.plugins.spotify.getSettings() };
}
exports.getSettings = getSettings;
function saveSettings(newSettings, newSpotifySettings) {
deemix_1.default.settings.save(newSettings, exports.configFolder);
settings = newSettings;
exports.plugins.spotify.saveSettings(newSpotifySettings);
}
exports.saveSettings = saveSettings;
let queueOrder = [];
const queue = {};
let currentJob = null;
restoreQueueFromDisk();
function getQueue() {
const result = {
queue,
queueOrder
};
if (currentJob && currentJob !== true) {
result.current = currentJob.downloadObject.getSlimmedDict();
}
return result;
}
exports.getQueue = getQueue;
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 = [];
let link = '';
const requestUUID = uuid_1.v4();
if (url.length > 1) {
exports.listener.send('startGeneratingItems', { uuid: requestUUID, total: url.length });
}
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);
}
if (Array.isArray(downloadObj)) {
downloadObjs = downloadObjs.concat(downloadObj);
}
else if (downloadObj)
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 });
});
}
if (url.length > 1) {
exports.listener.send('finishGeneratingItems', { uuid: requestUUID, total: downloadObjs.length });
}
const slimmedObjects = [];
downloadObjs.forEach((downloadObj, pos) => {
// Check if element is already in queue
if (Object.keys(queue).includes(downloadObj.uuid)) {
exports.listener.send('alreadyInQueue', downloadObj.getEssentialDict());
delete downloadObjs[pos];
return;
}
// Save queue status when adding something to the queue
if (!fs_1.default.existsSync(exports.configFolder + 'queue'))
fs_1.default.mkdirSync(exports.configFolder + 'queue');
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';
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());
});
const isSingleObject = downloadObjs.length === 1;
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 {
if (currentJob !== null || queueOrder.length === 0) {
// Should not start another download
return null;
}
currentJob = true; // lock currentJob
const currentUUID = queueOrder.shift() || '';
console.log(currentUUID);
queue[currentUUID].status = 'downloading';
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);
downloadObject = yield exports.plugins[downloadObject.plugin].convert(dz, downloadObject, settings, exports.listener);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`, JSON.stringify(Object.assign(Object.assign({}, downloadObject.toDict()), { status: 'inQueue' })));
break;
}
currentJob = new Downloader(dz, downloadObject, settings, exports.listener);
exports.listener.send('startDownload', currentUUID);
yield currentJob.start();
if (!downloadObject.isCanceled) {
// Set status
if (downloadObject.failed === downloadObject.size) {
queue[currentUUID].status = 'failed';
}
else if (downloadObject.failed > 0) {
queue[currentUUID].status = 'withErrors';
}
else {
queue[currentUUID].status = 'completed';
}
const savedObject = downloadObject.getSlimmedDict();
savedObject.status = queue[currentUUID].status;
// Save queue status
queue[currentUUID] = savedObject;
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${currentUUID}.json`, JSON.stringify(savedObject));
}
console.log(queueOrder);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
currentJob = null;
} while (queueOrder.length);
});
}
exports.startQueue = startQueue;
function cancelDownload(uuid) {
if (Object.keys(queue).includes(uuid)) {
switch (queue[uuid].status) {
case 'downloading':
currentJob.downloadObject.isCanceled = true;
exports.listener.send('cancellingCurrentItem', uuid);
break;
case 'inQueue':
queueOrder.splice(queueOrder.indexOf(uuid), 1);
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
// break
// eslint-disable-next-line no-fallthrough
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`);
delete queue[uuid];
}
}
exports.cancelDownload = cancelDownload;
function cancelAllDownloads() {
queueOrder = [];
let currentItem = null;
Object.values(queue).forEach((downloadObject) => {
if (downloadObject.status === 'downloading') {
currentJob.downloadObject.isCanceled = true;
exports.listener.send('cancellingCurrentItem', downloadObject.uuid);
currentItem = downloadObject.uuid;
}
fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`);
delete queue[downloadObject.uuid];
});
fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(queueOrder));
exports.listener.send('removedAllDownloads', currentItem);
}
exports.cancelAllDownloads = cancelAllDownloads;
function clearCompletedDownloads() {
Object.values(queue).forEach((downloadObject) => {
if (downloadObject.status === 'completed') {
fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`);
delete queue[downloadObject.uuid];
}
});
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) => {
if (filename === 'order.json') {
queueOrder = JSON.parse(fs_1.default.readFileSync(exports.configFolder + `queue${path_1.sep}order.json`).toString());
}
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;
}
queue[downloadObject.uuid] = downloadObject.getEssentialDict();
queue[downloadObject.uuid].status = 'inQueue';
}
else {
queue[currentItem.uuid] = currentItem;
}
}
});
}
exports.restoreQueueFromDisk = restoreQueueFromDisk;

View File

@ -1,26 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerMiddlewares = void 0;
const express_1 = __importDefault(require("express"));
const morgan_1 = __importDefault(require("morgan"));
const cookie_parser_1 = __importDefault(require("cookie-parser"));
const express_session_1 = __importDefault(require("express-session"));
const paths_1 = require("./helpers/paths");
function registerMiddlewares(app) {
if (process.env.NODE_ENV !== 'test') {
app.use(morgan_1.default('dev'));
}
app.use(express_1.default.json());
app.use(express_1.default.urlencoded({ extended: false }));
app.use(cookie_parser_1.default());
app.use(express_session_1.default({
secret: 'U2hoLCBpdHMgYSBzZWNyZXQh',
resave: true,
saveUninitialized: true
}));
app.use(express_1.default.static(paths_1.WEBUI_DIR));
}
exports.registerMiddlewares = registerMiddlewares;

View File

@ -1,3 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = [];

View File

@ -1,55 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/album-search/';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
if (!req.query) {
return res.status(400).send();
}
const { term, start, nb, ack } = parseQuery(req.query);
if (!term || term.trim() === '') {
return res.status(400).send();
}
const albums = yield dz.api.search_album(term, { start, nb });
const output = {
data: albums,
total: albums.data.length,
ack
};
return res.send(output);
});
const apiHandler = { path, handler };
exports.default = apiHandler;
function parseQuery(query) {
let startingPoint = 0;
if (typeof query.start !== 'undefined') {
startingPoint = parseInt(query.start);
}
let newNb = 30;
if (typeof query.nb !== 'undefined') {
newNb = parseInt(query.nb);
}
return {
term: query.term,
start: startingPoint,
nb: newNb,
ack: query.ack
};
}
// function getAlbums(term: string, start: number, nb: number): any[] {
// return []
// }

View File

@ -1,46 +0,0 @@
"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 });
// @ts-expect-error
const deemix_1 = __importDefault(require("deemix"));
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/analyzeLink';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (!req.query || !req.query.term) {
return res.status(400).send({ errorMessage: 'No term specified', errorCode: 'AL01' });
}
const { term: linkToAnalyze } = req.query;
const [, linkType, linkId] = yield deemix_1.default.parseLink(linkToAnalyze);
const isTrackOrAlbum = ['track', 'album'].includes(linkType);
if (isTrackOrAlbum) {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const apiMethod = linkType === 'track' ? 'get_track' : 'get_album';
const resBody = yield dz.api[apiMethod](linkId);
return res.status(200).send(resBody);
}
return res.status(400).send({ errorMessage: 'Not supported', errorCode: 'AL02' });
}
catch (error) {
return res
.status(500)
.send({ errorMessage: 'The server had a problem. Please try again', errorObject: error, errorCode: 'AL03' });
}
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,19 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/changeAccount';
const handler = (req, res) => {
if (!req.query || !req.query.child) {
return res.status(400).send({ errorMessage: 'No child specified', errorCode: 'CA01' });
}
const { child: accountNum } = req.query;
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const accountData = dz.change_account(accountNum);
return res.status(200).send(accountData);
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,42 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const primitive_checks_1 = require("../../../helpers/primitive-checks");
const errors_1 = require("../../../helpers/errors");
const path = '/getChartTracks';
const handler = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
if (primitive_checks_1.isObjectEmpy(req.query) || !req.query.id) {
throw new errors_1.BadRequestError();
}
const playlistId = req.query.id;
const index = req.query.index;
const limit = req.query.limit;
const response = yield dz.api.get_playlist_tracks(playlistId, { index, limit });
res.status(200).send(response);
next();
}
catch (error) {
if (errors_1.isBadRequestError(error)) {
errors_1.consoleError(error.message);
res.status(400).send();
return next();
}
}
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,38 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getCharts';
let chartsCache;
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!chartsCache) {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const chartsData = yield dz.api.get_countries_charts();
const countries = [];
chartsData.forEach((country) => {
countries.push({
title: country.title.replace('Top ', ''),
id: country.id,
picture_small: country.picture_small,
picture_medium: country.picture_medium,
picture_big: country.picture_big
});
});
chartsCache = { data: countries };
}
res.send(chartsCache);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,27 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getHome';
let homeCache;
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
if (!homeCache) {
homeCache = yield dz.api.get_chart(0, { limit: 30 });
}
res.send(homeCache);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,11 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/getQueue';
// let homeCache: any
const handler = (_, res) => {
const result = main_1.getQueue();
res.send(result);
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,9 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/getSettings';
const handler = (_, res) => {
res.send(main_1.getSettings());
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,95 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getTracklist';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const list_id = String(req.query.id);
const list_type = String(req.query.type);
switch (list_type) {
case 'artist': {
const artistAPI = yield dz.api.get_artist(list_id);
artistAPI.releases = yield dz.gw.get_artist_discography_tabs(list_id, { limit: 100 });
res.send(artistAPI);
break;
}
case 'spotifyplaylist':
case 'spotify_playlist': {
if (!main_1.plugins.spotify.enabled) {
res.send({
collaborative: false,
description: '',
external_urls: { spotify: null },
followers: { total: 0, href: null },
id: null,
images: [],
name: 'Something went wrong',
owner: {
display_name: 'Error',
id: null
},
public: true,
tracks: [],
type: 'playlist',
uri: null
});
break;
}
const sp = main_1.plugins.spotify.sp;
let playlist = yield sp.getPlaylist(list_id);
playlist = playlist.body;
let tracklist = playlist.tracks.items;
while (playlist.tracks.next) {
const regExec = /offset=(\d+)&limit=(\d+)/g.exec(playlist.tracks.next);
const offset = regExec[1];
const limit = regExec[2];
const playlistTracks = yield sp.getPlaylistTracks(list_id, { offset, limit });
playlist.tracks = playlistTracks.body;
tracklist = tracklist.concat(playlist.tracks.items);
}
tracklist.forEach((item, i) => {
tracklist[i] = item.track;
tracklist[i].selected = false;
});
playlist.tracks = tracklist;
res.send(playlist);
break;
}
default: {
const releaseAPI = yield dz.api[`get_${list_type}`](list_id);
let releaseTracksAPI = yield dz.api[`get_${list_type}_tracks`](list_id);
releaseTracksAPI = releaseTracksAPI.data;
const tracks = [];
const showdiscs = list_type === 'album' &&
releaseTracksAPI.length &&
releaseTracksAPI[releaseTracksAPI.length - 1].disk_number !== 1;
let current_disk = 0;
releaseTracksAPI.forEach((track) => {
if (showdiscs && parseInt(track.disk_number) !== current_disk) {
current_disk = parseInt(track.disk_number);
tracks.push({ type: 'disc_separator', number: current_disk });
}
track.selected = false;
tracks.push(track);
});
releaseAPI.tracks = tracks;
res.send(releaseAPI);
break;
}
}
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,37 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getUserAlbums';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
let data;
if (dz.logged_in) {
const userID = dz.current_user.id;
try {
data = yield dz.api.get_user_albums(userID, { limit: -1 });
data = data.data;
}
catch (_a) {
data = yield dz.gw.get_user_albums(userID, { limit: -1 });
}
}
else {
data = { error: 'notLoggedIn' };
}
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,37 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getUserArtists';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
let data;
if (dz.logged_in) {
const userID = dz.current_user.id;
try {
data = yield dz.api.get_user_artists(userID, { limit: -1 });
data = data.data;
}
catch (_a) {
data = yield dz.gw.get_user_artists(userID, { limit: -1 });
}
}
else {
data = { error: 'notLoggedIn' };
}
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,47 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getUserFavorites';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
let result = {};
if (dz.logged_in) {
const userID = dz.current_user.id;
try {
let data;
data = yield dz.api.get_user_playlists(userID, { limit: -1 });
result.playlists = data.data;
data = yield dz.api.get_user_albums(userID, { limit: -1 });
result.albums = data.data;
data = yield dz.api.get_user_artists(userID, { limit: -1 });
result.artists = data.data;
data = yield dz.api.get_user_tracks(userID, { limit: -1 });
result.tracks = data.data;
}
catch (_a) {
result.playlists = yield dz.gw.get_user_playlists(userID, { limit: -1 });
result.albums = yield dz.gw.get_user_albums(userID, { limit: -1 });
result.artists = yield dz.gw.get_user_artists(userID, { limit: -1 });
result.tracks = yield dz.gw.get_user_tracks(userID, { limit: -1 });
}
}
else {
result = { error: 'notLoggedIn' };
}
res.send(result);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,37 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getUserPlaylists';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
let data;
if (dz.logged_in) {
const userID = dz.current_user.id;
try {
data = yield dz.api.get_user_playlists(userID, { limit: -1 });
data = data.data;
}
catch (_a) {
data = yield dz.gw.get_user_playlists(userID, { limit: -1 });
}
}
else {
data = { error: 'notLoggedIn' };
}
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,41 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/getUserSpotifyPlaylists';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
let data;
if (main_1.plugins.spotify.enabled) {
const sp = main_1.plugins.spotify.sp;
const username = req.query.spotifyUser;
data = [];
let playlists = yield sp.getUserPlaylists(username);
playlists = playlists.body;
let playlistList = playlists.items;
while (playlists.next) {
const regExec = /offset=(\d+)&limit=(\d+)/g.exec(playlists.next);
const offset = regExec[1];
const limit = regExec[2];
const newPlaylists = yield sp.getUserPlaylists(username, { offset, limit });
playlists = newPlaylists.body;
playlistList = playlistList.concat(playlists.items);
}
playlistList.forEach((playlist) => {
data.push(main_1.plugins.spotify._convertPlaylistStructure(playlist));
});
}
else {
data = { error: 'spotifyNotEnabled' };
}
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,37 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/getUserTracks';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
let data;
if (dz.logged_in) {
const userID = dz.current_user.id;
try {
data = yield dz.api.get_user_tracks(userID, { limit: -1 });
data = data.data;
}
catch (_a) {
data = yield dz.gw.get_user_tracks(userID, { limit: -1 });
}
}
else {
data = { error: 'notLoggedIn' };
}
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,41 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const analyzeLink_1 = __importDefault(require("./analyzeLink"));
const changeAccount_1 = __importDefault(require("./changeAccount"));
const getHome_1 = __importDefault(require("./getHome"));
const getCharts_1 = __importDefault(require("./getCharts"));
const mainSearch_1 = __importDefault(require("./mainSearch"));
const search_1 = __importDefault(require("./search"));
const getTracklist_1 = __importDefault(require("./getTracklist"));
const albumSearch_1 = __importDefault(require("./albumSearch"));
const getChartTracks_1 = __importDefault(require("./getChartTracks"));
const getSettings_1 = __importDefault(require("./getSettings"));
const getUserTracks_1 = __importDefault(require("./getUserTracks"));
const getUserAlbums_1 = __importDefault(require("./getUserAlbums"));
const getUserArtists_1 = __importDefault(require("./getUserArtists"));
const getUserPlaylists_1 = __importDefault(require("./getUserPlaylists"));
const getUserSpotifyPlaylists_1 = __importDefault(require("./getUserSpotifyPlaylists"));
const getUserFavorites_1 = __importDefault(require("./getUserFavorites"));
const getQueue_1 = __importDefault(require("./getQueue"));
exports.default = [
albumSearch_1.default,
changeAccount_1.default,
analyzeLink_1.default,
getHome_1.default,
getCharts_1.default,
getChartTracks_1.default,
mainSearch_1.default,
search_1.default,
getTracklist_1.default,
getSettings_1.default,
getUserTracks_1.default,
getUserAlbums_1.default,
getUserArtists_1.default,
getUserPlaylists_1.default,
getUserSpotifyPlaylists_1.default,
getUserFavorites_1.default,
getQueue_1.default
];

View File

@ -1,66 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/mainSearch';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const term = String(req.query.term);
const results = yield dz.gw.search(term);
const order = [];
results.ORDER.forEach((element) => {
if (['TOP_RESULT', 'TRACK', 'ALBUM', 'ARTIST', 'PLAYLIST'].includes(element))
order.push(element);
});
if (results.TOP_RESULT && results.TOP_RESULT.length) {
const originalTopResult = results.TOP_RESULT[0];
const topResult = {
type: originalTopResult.__TYPE__
};
switch (topResult.type) {
case 'artist':
topResult.id = originalTopResult.ART_ID;
topResult.picture = `https://e-cdns-images.dzcdn.net/images/artist/${originalTopResult.ART_PICTURE}`;
topResult.title = originalTopResult.ART_NAME;
topResult.nb_fan = originalTopResult.NB_FAN;
break;
case 'album':
topResult.id = originalTopResult.ALB_ID;
topResult.picture = `https://e-cdns-images.dzcdn.net/images/cover/${originalTopResult.ALB_PICTURE}`;
topResult.title = originalTopResult.ALB_TITLE;
topResult.artist = originalTopResult.ART_NAME;
topResult.nb_song = originalTopResult.NUMBER_TRACK;
break;
case 'playlist':
topResult.id = originalTopResult.PLAYLIST_ID;
topResult.picture = `https://e-cdns-images.dzcdn.net/images/${originalTopResult.PICTURE_TYPE}/${originalTopResult.PLAYLIST_PICTURE}`;
topResult.title = originalTopResult.TITLE;
topResult.artist = originalTopResult.PARENT_USERNAME;
topResult.nb_song = originalTopResult.NB_SONG;
break;
default:
topResult.id = '0';
topResult.picture = 'https://e-cdns-images.dzcdn.net/images/cover';
break;
}
topResult.picture += '/156x156-000000-80-0-0.jpg';
topResult.link = `https://deezer.com/${topResult.type}/${topResult.id}`;
results.TOP_RESULT = [topResult];
}
results.ORDER = order;
res.send(results);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1 +0,0 @@
"use strict";

View File

@ -1,52 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/search';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const term = String(req.query.term);
const type = String(req.query.type);
const start = parseInt(String(req.query.start));
const nb = parseInt(String(req.query.nb));
let data;
switch (type) {
case 'track':
data = yield dz.api.search_track(term, { limit: nb, index: start });
break;
case 'album':
data = yield dz.api.search_album(term, { limit: nb, index: start });
break;
case 'artist':
data = yield dz.api.search_artist(term, { limit: nb, index: start });
break;
case 'playlist':
data = yield dz.api.search_playlist(term, { limit: nb, index: start });
break;
case 'radio':
data = yield dz.api.search_radio(term, { limit: nb, index: start });
break;
case 'user':
data = yield dz.api.search_user(term, { limit: nb, index: start });
break;
default:
data = yield dz.api.search(term, { limit: nb, index: start });
break;
}
data.type = type;
res.send(data);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,3 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = [];

View File

@ -1,44 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/addToQueue';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
const url = req.query.url.split(/[\s;]+/);
let bitrate = req.query.bitrate;
if (bitrate === 'null')
bitrate = main_1.getSettings().settings.maxBitrate;
let obj;
try {
obj = yield main_1.addToQueue(dz, url, bitrate);
}
catch (e) {
switch (e.name) {
case 'NotLoggedIn':
res.send({ result: false, errid: e.name, data: { url, bitrate } });
main_1.listener.send('loginNeededToDownload');
break;
default:
console.error(e);
res.send({ result: false, errid: e.name, data: { url, bitrate } });
break;
}
return;
}
res.send({ result: true, data: { url, bitrate, obj } });
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/cancelAllDownloads';
const handler = (_, res) => {
main_1.cancelAllDownloads();
res.send({ result: true });
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,23 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const login_arl_1 = __importDefault(require("./login-arl"));
const addToQueue_1 = __importDefault(require("./addToQueue"));
const loginWithCredentials_1 = __importDefault(require("./loginWithCredentials"));
const cancelAllDownloads_1 = __importDefault(require("./cancelAllDownloads"));
const removeFinishedDownloads_1 = __importDefault(require("./removeFinishedDownloads"));
const removeFromQueue_1 = __importDefault(require("./removeFromQueue"));
const logout_1 = __importDefault(require("./logout"));
const saveSettings_1 = __importDefault(require("./saveSettings"));
exports.default = [
login_arl_1.default,
addToQueue_1.default,
loginWithCredentials_1.default,
cancelAllDownloads_1.default,
removeFinishedDownloads_1.default,
removeFromQueue_1.default,
logout_1.default,
saveSettings_1.default
];

View File

@ -1,60 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const LoginStatus = {
NOT_AVAILABLE: -1,
FAILED: 0,
SUCCESS: 1,
ALREADY_LOGGED: 2,
FORCED_SUCCESS: 3
};
const path = '/login-arl';
const handler = (req, res, _) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
if (!req.query) {
return res.status(400).send();
}
if (!req.query.arl) {
return res.status(400).send();
}
const loginParams = [req.query.arl];
// TODO Handle the child === 0 case, don't want to rely on the login_via_arl default param (it may change in the
// future)
if (req.query.child) {
loginParams.push(req.query.child);
}
let response;
if (process.env.NODE_ENV !== 'test') {
if (!dz.logged_in) {
response = yield dz.login_via_arl(...loginParams);
response = response ? 1 : 0;
}
else {
response = LoginStatus.ALREADY_LOGGED;
}
}
else {
const testDz = new deezer_js_1.Deezer();
response = yield testDz.login_via_arl(...loginParams);
}
if (!(yield main_1.isDeezerAvailable()))
response = LoginStatus.NOT_AVAILABLE;
const returnValue = { status: response, arl: req.query.arl, user: dz.current_user };
main_1.startQueue(dz);
return res.status(200).send(returnValue);
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,27 +0,0 @@
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/loginWithCredentials';
const handler = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
const { email, password } = req.body;
let accessToken = req.body.accessToken;
if (!accessToken) {
accessToken = yield main_1.getAccessToken(email, password);
}
let arl;
if (accessToken)
arl = yield main_1.getArlFromAccessToken(accessToken);
console.log({ accessToken, arl });
res.send({ accessToken, arl });
});
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../../../main");
const path = '/logout';
const handler = (req, res) => {
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
res.send({ logged_out: true });
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/removeFinishedDownloads';
const handler = (_, res) => {
main_1.clearCompletedDownloads();
res.send({ result: true });
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,16 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/removeFromQueue';
const handler = (req, res) => {
const { uuid } = req.query;
if (uuid) {
main_1.cancelDownload(uuid);
res.send({ result: true });
}
else {
res.send({ result: false });
}
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const main_1 = require("../../../main");
const path = '/saveSettings';
const handler = (req, res) => {
const { settings, spotifySettings } = req.query;
main_1.saveSettings(settings, spotifySettings);
main_1.listener.send('updateSettings', { settings, spotifySettings });
res.send({ result: true });
};
const apiHandler = { path, handler };
exports.default = apiHandler;

View File

@ -1,42 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerApis = void 0;
const get_1 = __importDefault(require("./get"));
const delete_1 = __importDefault(require("./delete"));
const post_1 = __importDefault(require("./post"));
const patch_1 = __importDefault(require("./patch"));
const prependApiPath = (path) => `/api${path}`;
const methods = [
{
method: 'get',
endpoints: get_1.default
},
{
method: 'delete',
endpoints: delete_1.default
},
{
method: 'post',
endpoints: post_1.default
},
{
method: 'patch',
endpoints: patch_1.default
}
];
function registerApis(app) {
methods.forEach(({ method, endpoints }) => {
endpoints.forEach(endpoint => {
// @ts-expect-error
app[method](prependApiPath(endpoint.path), endpoint.handler);
});
});
// Fallback, for SPA mode
app.get('*', (_, res) => {
res.redirect('/');
});
}
exports.registerApis = registerApis;

View File

@ -1,53 +0,0 @@
"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 });
const express_1 = __importDefault(require("express"));
// @ts-expect-error
const deezer_js_1 = require("deezer-js");
const main_1 = require("../main");
const router = express_1.default.Router();
let update = null;
/**
* GET home page
*
* @since 0.0.0
*/
router.get('/', (_, res) => {
res.render('index', { title: 'deemix' });
});
router.get('/connect', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
if (!main_1.sessionDZ[req.session.id])
main_1.sessionDZ[req.session.id] = new deezer_js_1.Deezer();
const dz = main_1.sessionDZ[req.session.id];
if (!update) {
update = {
currentCommit: 'testing',
latestCommit: 'testing',
updateAvailable: false,
deemixVersion: main_1.deemixVersion
};
}
const result = {
update,
autologin: !dz.logged_in,
currentUser: dz.current_user,
deezerAvailable: yield main_1.isDeezerAvailable()
};
const queue = main_1.getQueue();
if (Object.keys(queue.queue).length > 0) {
result.queue = queue;
}
res.send(result);
}));
exports.default = router;

View File

@ -1,2 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -1,30 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerWebsocket = void 0;
const errors_1 = require("../helpers/errors");
const modules_1 = __importDefault(require("./modules"));
// ? Is this needed?
// ? https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
const registerWebsocket = (wss) => {
wss.on('connection', ws => {
ws.on('message', message => {
errors_1.consoleInfo(`Received: ${message}`);
const data = JSON.parse(message.toString());
modules_1.default.forEach(module => {
if (data.key === module.eventName) {
module.cb(data.data, ws, wss);
}
});
});
});
wss.on('error', () => {
errors_1.consoleError('An error occurred to the WebSocket server.');
});
wss.on('close', () => {
errors_1.consoleInfo('Connection to the WebSocket server closed.');
});
};
exports.registerWebsocket = registerWebsocket;

View File

@ -1 +0,0 @@
"use strict";

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("../../helpers/errors");
const main_1 = require("../../main");
const eventName = 'cancelAllDownloads';
const cb = (_, __, ___) => {
main_1.cancelAllDownloads();
errors_1.consoleInfo(`Queue cleared`);
};
exports.default = { eventName, cb };

View File

@ -1 +0,0 @@
"use strict";

View File

@ -1,10 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const saveSettings_1 = __importDefault(require("./saveSettings"));
const removeFinishedDownloads_1 = __importDefault(require("./removeFinishedDownloads"));
const removeFromQueue_1 = __importDefault(require("./removeFromQueue"));
const cancelAllDownloads_1 = __importDefault(require("./cancelAllDownloads"));
exports.default = [saveSettings_1.default, removeFinishedDownloads_1.default, removeFromQueue_1.default, cancelAllDownloads_1.default];

View File

@ -1 +0,0 @@
"use strict";

View File

@ -1 +0,0 @@
"use strict";

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("../../helpers/errors");
const main_1 = require("../../main");
const eventName = 'removeFinishedDownloads';
const cb = (_, __, ___) => {
main_1.clearCompletedDownloads();
errors_1.consoleInfo('Completed downloads cleared');
};
exports.default = { eventName, cb };

View File

@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("../../helpers/errors");
const main_1 = require("../../main");
const eventName = 'removeFromQueue';
const cb = (data, __, ___) => {
main_1.cancelDownload(data);
errors_1.consoleInfo(`Cancelled ${data}`);
};
exports.default = { eventName, cb };

View File

@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("../../helpers/errors");
const main_1 = require("../../main");
const eventName = 'saveSettings';
const cb = (data, _, __) => {
const { settings, spotifySettings } = data;
main_1.saveSettings(settings, spotifySettings);
errors_1.consoleInfo('Settings saved');
main_1.listener.send('updateSettings', { settings, spotifySettings });
};
exports.default = { eventName, cb };

View File

@ -3,19 +3,72 @@
"version": "0.1.0",
"private": true,
"scripts": {
"start": "nodemon src/app.ts",
"start": "webpack --watch",
"start-build": "node dist/app.js",
"lint": "eslint \"./{src, tests}/**\" --fix",
"lint-build": "eslint \"./src/**\" --fix",
"prebuild": "yarn lint-build",
"build": "tsc",
"build": "webpack --env production",
"test": "jest",
"test-watch": "jest --watch"
},
"bin": "./dist/main.js",
"bin": "./dist/app.js",
"pkg": {
"scripts": "./dist/**/*.js",
"assets": "../webui/public/**/*",
"targets": [ "node16-linux-x64", "node16-win-x64", "node16-macos-x64"]
"targets": [
"node16-linux-x64",
"node16-win-x64",
"node16-macos-x64"
]
},
"dependencies": {
"bufferutil": "4.0.3",
"cookie-parser": "1.4.5",
"debug": "2.6.9",
"deemix": "3.0.3",
"deezer-js": "^1.0.0",
"dotenv": "8.2.0",
"express": "4.17.1",
"express-session": "^1.17.1",
"memorystore": "1.6.6",
"morgan": "1.10.0",
"ramda": "0.27.1",
"utf-8-validate": "5.0.5",
"uuid": "8.3.2",
"ws": "7.4.5",
"yargs": "17.0.1"
},
"devDependencies": {
"@nuxtjs/eslint-config": "6.0.0",
"@types/cookie-parser": "1.4.2",
"@types/debug": "4.1.5",
"@types/express": "4.17.11",
"@types/express-session": "^1.17.3",
"@types/jest": "26.0.22",
"@types/morgan": "1.9.2",
"@types/node": "14.14.37",
"@types/ramda": "0.27.40",
"@types/supertest": "2.0.11",
"@types/uuid": "8.3.0",
"@types/ws": "7.4.1",
"@types/yargs": "17.0.0",
"@typescript-eslint/eslint-plugin": "4.21.0",
"@typescript-eslint/parser": "4.21.0",
"eslint": "7.23.0",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-prettier": "3.3.1",
"jest": "26.6.3",
"nodemon": "2.0.7",
"nodemon-webpack-plugin": "4.5.2",
"prettier": "2.2.1",
"supertest": "6.1.3",
"ts-jest": "26.5.4",
"ts-loader": "9.2.3",
"ts-node": "9.1.1",
"ts-node-dev": "1.1.6",
"typescript": "4.2.4",
"webpack": "5.41.1",
"webpack-cli": "4.7.2"
}
}

View File

@ -16,6 +16,8 @@ import { registerWebsocket } from './websocket'
import type { Arguments } from './types'
import { consoleInfo } from './helpers/errors'
export { getSettings } from './main'
// TODO: Remove type assertion while keeping correct types
const argv = yargs(hideBin(process.argv)).options({
port: { type: 'string', default: '6595' },
@ -26,8 +28,8 @@ const DEEMIX_PORT = normalizePort(process.env.DEEMIX_PORT ?? argv.port)
const DEEMIX_HOST = process.env.DEEMIX_HOST ?? argv.host
const debug = initDebug('deemix-gui:server')
export const app: Application = express()
export const wss = new WsServer({ noServer: true })
const app: Application = express()
const server = http.createServer(app)
/* === Middlewares === */

View File

@ -1,4 +1,4 @@
import path from 'path'
export const ROOT_DIR = path.resolve(path.join(__dirname, '..', '..', '..'))
export const ROOT_DIR = path.resolve(path.join(__dirname, '..', '..'))
export const WEBUI_DIR = path.join(ROOT_DIR, 'webui', 'public')

View File

@ -19,7 +19,7 @@ let settings: any = deemix.settings.load(configFolder)
export const getAccessToken = deemix.utils.deezer.getAccessToken
export const getArlFromAccessToken = deemix.utils.deezer.getArlFromAccessToken
export const deemixVersion = require('../../node_modules/deemix/package.json').version
export const deemixVersion = require('../node_modules/deemix/package.json').version
let deezerAvailable: boolean | null = null
export async function isDeezerAvailable(): Promise<boolean> {

View File

@ -6,6 +6,8 @@ import session from 'express-session'
import { WEBUI_DIR } from './helpers/paths'
const MemoryStore = require('memorystore')(session)
declare module 'express-session' {
export interface SessionData {
dz: any
@ -22,6 +24,9 @@ export function registerMiddlewares(app: Application) {
app.use(cookieParser())
app.use(
session({
store: new MemoryStore({
checkPeriod: 86400000 // prune expired entries every 24h
}),
secret: 'U2hoLCBpdHMgYSBzZWNyZXQh',
resave: true,
saveUninitialized: true

View File

@ -9,7 +9,6 @@ export interface RawAlbumQuery {
term: string
start?: string
nb?: string
ack: number
}
export interface AlbumSearchParams extends Omit<RawAlbumQuery, 'start' | 'nb'> {
@ -20,7 +19,6 @@ export interface AlbumSearchParams extends Omit<RawAlbumQuery, 'start' | 'nb'> {
export interface AlbumResponse {
data: any[]
total: number
ack: RawAlbumQuery['ack']
}
const path: ApiHandler['path'] = '/album-search/'
@ -33,18 +31,19 @@ const handler: RequestHandler<{}, {}, {}, RawAlbumQuery> = async (req, res) => {
return res.status(400).send()
}
const { term, start, nb, ack } = parseQuery(req.query)
const { term, start, nb } = parseQuery(req.query)
if (!term || term.trim() === '') {
return res.status(400).send()
}
const albums = await dz.api.search_album(term, { start, nb })
const results = await dz.gw.search_music(term, 'ALBUM', { index: start, limit: nb })
const albums = await Promise.all(results.data.map((c: any) => getAlbumDetails(dz, c.ALB_ID)))
const output: AlbumResponse = {
data: albums,
total: albums.data.length,
ack
total: albums.length
}
return res.send(output)
@ -52,8 +51,6 @@ const handler: RequestHandler<{}, {}, {}, RawAlbumQuery> = async (req, res) => {
const apiHandler = { path, handler }
export default apiHandler
function parseQuery(query: RawAlbumQuery): AlbumSearchParams {
let startingPoint = 0
@ -70,11 +67,26 @@ function parseQuery(query: RawAlbumQuery): AlbumSearchParams {
return {
term: query.term,
start: startingPoint,
nb: newNb,
ack: query.ack
nb: newNb
}
}
// function getAlbums(term: string, start: number, nb: number): any[] {
// return []
// }
async function getAlbumDetails(dz: any, albumId: string): Promise<any> {
const result = await dz.gw.get_album_page(albumId)
const output = result.DATA
let duration = 0
result.SONGS.data.forEach((s: any) => {
if ('DURATION' in s) {
duration += parseInt(s.DURATION)
}
})
output.DURATION = duration
output.NUMBER_TRACK = result.SONGS.total
output.LINK = `https://deezer.com/album/${output.ALB_ID}`
return output
}
export { apiHandler, getAlbumDetails }

View File

@ -4,8 +4,9 @@ import getHome from './getHome'
import getCharts from './getCharts'
import mainSearch from './mainSearch'
import search from './search'
import newReleases from './newReleases'
import getTracklist from './getTracklist'
import albumSearch from './albumSearch'
import { apiHandler as albumSearch } from './albumSearch'
import getChartTracks from './getChartTracks'
import getSettings from './getSettings'
import getUserTracks from './getUserTracks'
@ -25,6 +26,7 @@ export default [
getChartTracks,
mainSearch,
search,
newReleases,
getTracklist,
getSettings,
getUserTracks,

View File

@ -0,0 +1,74 @@
// @ts-expect-error
import { Deezer } from 'deezer-js'
import { ApiHandler } from '../../../types'
import { sessionDZ } from '../../../main'
import { getAlbumDetails } from './albumSearch'
const path: ApiHandler['path'] = '/newReleases'
const handler: ApiHandler['handler'] = async (req, res) => {
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
const dz = sessionDZ[req.session.id]
const results = await dz.gw.get_page('channels/explore')
const music_section = results.sections.find((e: any) =>
e.section_id.includes('module_id=83718b7b-5503-4062-b8b9-3530e2e2cefa')
)
const channels = music_section.items.map((e: any) => e.target)
const newReleasesByChannel = <any[][]>await Promise.all(channels.map((c: string) => channelNewReleases(dz, c)))
const seen = new Set()
const distinct: any[] = []
newReleasesByChannel.forEach(l => {
l.forEach(r => {
if (!seen.has(r.ALB_ID)) {
seen.add(r.ALB_ID)
distinct.push(r)
}
})
})
distinct.sort((a, b) =>
a.DIGITAL_RELEASE_DATE < b.DIGITAL_RELEASE_DATE ? 1 : b.DIGITAL_RELEASE_DATE < a.DIGITAL_RELEASE_DATE ? -1 : 0
)
const now = Date.now()
const delta = 8 * 24 * 60 * 60 * 1000
const recent = distinct.filter((x: any) => now - Date.parse(x.DIGITAL_RELEASE_DATE) < delta)
const albums = await Promise.all(recent.map((c: any) => getAlbumDetails(dz, c.ALB_ID)))
const output = {
data: albums,
total: albums.length
}
return res.send(output)
}
const apiHandler: ApiHandler = { path, handler }
export default apiHandler
async function channelNewReleases(dz: any, channelName: string): Promise<any[]> {
const channelData = await dz.gw.get_page(channelName)
const re = /^New.*releases$/
const newReleases = channelData.sections.find((e: any) => re.test(e.title))
if (!newReleases) {
return []
} else if ('target' in newReleases) {
const showAll = await dz.gw.get_page(newReleases.target)
return showAll.sections[0].items.map((e: any) => e.data)
} else if ('items' in newReleases) {
return newReleases.items.map((e: any) => e.data)
} else {
return []
}
}

View File

@ -6,15 +6,6 @@ import { sessionDZ, getQueue, deemixVersion, isDeezerAvailable } from '../main'
const router = express.Router()
let update: any = null
/**
* GET home page
*
* @since 0.0.0
*/
router.get('/', (_, res) => {
res.render('index', { title: 'deemix' })
})
router.get('/connect', async (req, res) => {
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
const dz = sessionDZ[req.session.id]

View File

@ -12,7 +12,7 @@
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
@ -49,7 +49,7 @@
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

48
server/webpack.config.js Normal file
View File

@ -0,0 +1,48 @@
const path = require('path');
const webpack = require('webpack');
const NodemonPlugin = require('nodemon-webpack-plugin');
module.exports = (env) => {
const isProduction = !!env.production;
const config = {
mode: isProduction ? 'production' : 'development',
entry: './src/app.ts',
devtool: isProduction ? false : 'eval-source-map',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
sourceMapFilename: '[file].map',
library: {
name: 'DeemixServer',
type: 'umd'
}
},
target: 'node',
plugins: [
new NodemonPlugin(),
new webpack.DefinePlugin({ "global.GENTLY": false }),
new webpack.ContextReplacementPlugin(
/[\/\\](express|keyv)[\/\\]/,
(data) => {
delete data.dependencies[0].critical;
return data;
},
),
new webpack.ContextReplacementPlugin(/yargs/),
],
}
return config
};

7063
server/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

5544
yarn.lock

File diff suppressed because it is too large Load Diff