diff --git a/server/dist/app.js b/server/dist/app.js index 2464603..16d288d 100644 --- a/server/dist/app.js +++ b/server/dist/app.js @@ -3,30 +3,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.wss = exports.app = void 0; const http_1 = __importDefault(require("http")); const express_1 = __importDefault(require("express")); +const ws_1 = require("ws"); const debug_1 = __importDefault(require("debug")); const middlewares_1 = require("./middlewares"); const routes_1 = __importDefault(require("./routes")); -const users_1 = __importDefault(require("./routes/users")); const port_1 = require("./helpers/port"); const server_callbacks_1 = require("./helpers/server-callbacks"); const register_1 = require("./routes/api/register"); +const websocket_1 = require("./websocket"); const PORT = port_1.normalizePort(process.env.PORT || '6595'); const debug = debug_1.default('deemix-gui:server'); -const app = express_1.default(); -const server = http_1.default.createServer(app); +exports.app = express_1.default(); +exports.wss = new ws_1.Server({ noServer: true }); +const server = http_1.default.createServer(exports.app); /* === Middlewares === */ -middlewares_1.registerMiddlewares(app); +middlewares_1.registerMiddlewares(exports.app); /* === Routes === */ -app.use('/', routes_1.default); -app.use('/users', users_1.default); +exports.app.use('/', routes_1.default); /* === APIs === */ -register_1.registerApis(app); +register_1.registerApis(exports.app); /* === Config === */ -app.set('port', PORT); +exports.app.set('port', PORT); /* === Server port === */ -server.listen(PORT); +if (process.env.NODE_ENV !== 'test') { + server.listen(PORT); +} +websocket_1.registerWebsocket(exports.wss); /* === Server callbacks === */ +server.on('upgrade', (request, socket, head) => { + exports.wss.handleUpgrade(request, socket, head, socket => { + exports.wss.emit('connection', socket, request); + }); +}); server.on('error', server_callbacks_1.getErrorCb(PORT)); server.on('listening', server_callbacks_1.getListeningCb(server, debug)); diff --git a/server/dist/helpers/errors.js b/server/dist/helpers/errors.js new file mode 100644 index 0000000..bcb94d3 --- /dev/null +++ b/server/dist/helpers/errors.js @@ -0,0 +1,41 @@ +"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 = (errorText) => console.info(prependDeemix(errorText)); +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; diff --git a/server/dist/helpers/paths.js b/server/dist/helpers/paths.js index 0dcbdc3..7c3a280 100644 --- a/server/dist/helpers/paths.js +++ b/server/dist/helpers/paths.js @@ -5,5 +5,5 @@ var __importDefault = (this && this.__importDefault) || function (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('../'); +exports.ROOT_DIR = path_1.default.resolve(path_1.default.join(__dirname, '..', '..', '..')); exports.WEBUI_DIR = path_1.default.join(exports.ROOT_DIR, 'webui', 'public'); diff --git a/server/dist/helpers/primitive-checks.js b/server/dist/helpers/primitive-checks.js new file mode 100644 index 0000000..21a57eb --- /dev/null +++ b/server/dist/helpers/primitive-checks.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isObjectEmpy = void 0; +const isObjectEmpy = (obj) => Object.keys(obj).length === 0; +exports.isObjectEmpy = isObjectEmpy; diff --git a/server/dist/main.js b/server/dist/main.js new file mode 100644 index 0000000..8949592 --- /dev/null +++ b/server/dist/main.js @@ -0,0 +1,234 @@ +"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.currentJob = exports.queue = exports.queueOrder = exports.saveSettings = exports.listener = exports.getArlFromAccessToken = exports.getAccessToken = exports.sessionDZ = exports.settings = 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 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.settings = deemix_1.default.settings.load(exports.configFolder); +exports.sessionDZ = {}; +exports.getAccessToken = deemix_1.default.utils.deezer.getAccessToken; +exports.getArlFromAccessToken = deemix_1.default.utils.deezer.getArlFromAccessToken; +const deemixPlugins = {}; +exports.listener = { + send(key, data) { + console.log(key, data); + app_1.wss.clients.forEach(client => { + if (client.readyState === ws_1.default.OPEN) { + client.send(JSON.stringify({ key, data })); + } + }); + } +}; +function saveSettings(newSettings) { + deemix_1.default.settings.save(newSettings, exports.configFolder); + exports.settings = newSettings; +} +exports.saveSettings = saveSettings; +exports.queueOrder = []; +exports.queue = {}; +exports.currentJob = null; +restoreQueueFromDisk(); +function addToQueue(dz, url, bitrate) { + return __awaiter(this, void 0, void 0, function* () { + if (!dz.logged_in) + throw new errors_1.NotLoggedIn(); + let downloadObjs = []; + 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 = yield deemix_1.default.generateDownloadObject(dz, link, bitrate, deemixPlugins, exports.listener); + if (Array.isArray(downloadObj)) { + downloadObjs.concat(downloadObj); + } + else { + downloadObjs.push(downloadObj); + } + } + if (url.length > 1) { + exports.listener.send("finishGeneratingItems", { uuid: requestUUID, total: downloadObjs.length }); + } + const isSingleObject = downloadObjs.length == 1; + const slimmedObjects = []; + downloadObjs.forEach((downloadObj) => { + // Check if element is already in queue + if (Object.keys(exports.queue).includes(downloadObj.uuid)) + throw new errors_1.AlreadyInQueue(downloadObj.getEssentialDict(), !isSingleObject); + // Save queue status when adding something to the queue + if (!fs_1.default.existsSync(exports.configFolder + 'queue')) + fs_1.default.mkdirSync(exports.configFolder + 'queue'); + exports.queueOrder.push(downloadObj.uuid); + fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(exports.queueOrder)); + exports.queue[downloadObj.uuid] = downloadObj.getEssentialDict(); + exports.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()); + }); + 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 (exports.currentJob !== null || exports.queueOrder.length === 0) { + // Should not start another download + return null; + } + exports.currentJob = true; // lock currentJob + const currentUUID = exports.queueOrder.shift() || ''; + console.log(currentUUID); + exports.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); + // Convert object here + break; + } + exports.currentJob = new Downloader(dz, downloadObject, exports.settings, exports.listener); + exports.listener.send('startDownload', currentUUID); + yield exports.currentJob.start(); + if (!downloadObject.isCanceled) { + // Set status + if (downloadObject.failed == downloadObject.size) { + exports.queue[currentUUID].status = 'failed'; + } + else if (downloadObject.failed > 0) { + exports.queue[currentUUID].status = 'withErrors'; + } + else { + exports.queue[currentUUID].status = 'completed'; + } + const savedObject = downloadObject.getSlimmedDict(); + savedObject.status = exports.queue[currentUUID].status; + // Save queue status + exports.queue[currentUUID] = savedObject; + fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}${currentUUID}.json`, JSON.stringify(savedObject)); + } + console.log(exports.queueOrder); + fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(exports.queueOrder)); + exports.currentJob = null; + } while (exports.queueOrder.length); + }); +} +exports.startQueue = startQueue; +function cancelDownload(uuid) { + if (Object.keys(exports.queue).includes(uuid)) { + switch (exports.queue[uuid].status) { + case 'downloading': + exports.currentJob.downloadObject.isCanceled = true; + exports.listener.send('cancellingCurrentItem', uuid); + break; + case 'inQueue': + exports.queueOrder.splice(exports.queueOrder.indexOf(uuid), 1); + fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(exports.queueOrder)); + // break + 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 exports.queue[uuid]; + } +} +exports.cancelDownload = cancelDownload; +function cancelAllDownloads() { + exports.queueOrder = []; + let currentItem = null; + Object.values(exports.queue).forEach((downloadObject) => { + if (downloadObject.status == 'downloading') { + exports.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 exports.queue[downloadObject.uuid]; + }); + fs_1.default.writeFileSync(exports.configFolder + `queue${path_1.sep}order.json`, JSON.stringify(exports.queueOrder)); + exports.listener.send('removedAllDownloads', currentItem); +} +exports.cancelAllDownloads = cancelAllDownloads; +function clearCompletedDownloads() { + Object.values(exports.queue).forEach((downloadObject) => { + if (downloadObject.status === 'completed') { + fs_1.default.unlinkSync(exports.configFolder + `queue${path_1.sep}${downloadObject.uuid}.json`); + delete exports.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') { + exports.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; + } + exports.queue[downloadObject.uuid] = downloadObject.getEssentialDict(); + exports.queue[downloadObject.uuid].status = 'inQueue'; + } + else { + exports.queue[currentItem.uuid] = currentItem; + } + } + }); +} +exports.restoreQueueFromDisk = restoreQueueFromDisk; diff --git a/server/dist/middlewares.js b/server/dist/middlewares.js index df63d29..6071c46 100644 --- a/server/dist/middlewares.js +++ b/server/dist/middlewares.js @@ -4,15 +4,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerMiddlewares = void 0; -const morgan_1 = __importDefault(require("morgan")); 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) { - app.use(morgan_1.default('dev')); + 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; diff --git a/server/dist/routes/api/get/albumSearch.js b/server/dist/routes/api/get/albumSearch.js new file mode 100644 index 0000000..ccec727 --- /dev/null +++ b/server/dist/routes/api/get/albumSearch.js @@ -0,0 +1,59 @@ +"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, next) => __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) { + res.status(400).send(); + return next(); + } + const { term, start, nb, ack } = parseQuery(req.query); + if (!term || term.trim() === '') { + res.status(400).send(); + return next(); + } + const albums = yield dz.api.search_album(term, { start, nb }); + const output = { + data: albums, + total: albums.data.length, + ack + }; + res.send(output); + res.send(); + next(); +}); +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 [] +// } diff --git a/server/dist/routes/api/get/albumSearch.spec.js b/server/dist/routes/api/get/albumSearch.spec.js new file mode 100644 index 0000000..c7ccaae --- /dev/null +++ b/server/dist/routes/api/get/albumSearch.spec.js @@ -0,0 +1,52 @@ +"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 utils_1 = require("../../../../tests/utils"); +describe('albumSearch requests', () => { + it('should respond 200 to calls with term', () => __awaiter(void 0, void 0, void 0, function* () { + const responseStatusCollector = []; + const batchCalls = [ + '/api/album-search/?term=eminem', + '/api/album-search/?term=eminem?start=10', + '/api/album-search/?term=eminem?ack=aa', + '/api/album-search/?term=eminem?ack=aa?start=10', + '/api/album-search/?term=eminem?ack=aa?start=10?nb=34' + ]; + for (const uri of batchCalls) { + responseStatusCollector.push((yield utils_1.appSendGet(uri)).status); + } + expect(responseStatusCollector).toMatchObject(new Array(batchCalls.length).fill(200)); + expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(200)); + })); + it('should respond 400 to calls without term', () => __awaiter(void 0, void 0, void 0, function* () { + const responseStatusCollector = []; + const batchCalls = [ + '/api/album-search/', + '/api/album-search/?start=10', + '/api/album-search/?ack=aa', + '/api/album-search/?ack=aa?start=10', + '/api/album-search/?ack=aa?start=10?nb=34' + ]; + for (const uri of batchCalls) { + responseStatusCollector.push((yield utils_1.appSendGet(uri)).status); + } + expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(400)); + })); + it('should respond the desired search result', () => __awaiter(void 0, void 0, void 0, function* () { + const res = (yield utils_1.appSendGet('/api/album-search/?term=eminem')).body; + expect(res.data.data.length).not.toBe(0); + })); + // TODO Understand whic should be the correct response + it.skip('should respond the desired search result with a start parameter', () => __awaiter(void 0, void 0, void 0, function* () { + const res = (yield utils_1.appSendGet('/api/album-search/?term=eminem?start=10')).body; + expect(res.data.data.length).not.toBe(0); + })); +}); diff --git a/server/dist/routes/api/get/analyzeLink.js b/server/dist/routes/api/get/analyzeLink.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/get/analyzeLink.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/get/changeAccount.js b/server/dist/routes/api/get/changeAccount.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/get/changeAccount.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/get/getChartTracks.js b/server/dist/routes/api/get/getChartTracks.js new file mode 100644 index 0000000..3de3e7c --- /dev/null +++ b/server/dist/routes/api/get/getChartTracks.js @@ -0,0 +1,42 @@ +"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; diff --git a/server/dist/routes/api/get/getCharts.js b/server/dist/routes/api/get/getCharts.js new file mode 100644 index 0000000..52889ad --- /dev/null +++ b/server/dist/routes/api/get/getCharts.js @@ -0,0 +1,38 @@ +"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; diff --git a/server/dist/routes/api/get/getHome.js b/server/dist/routes/api/get/getHome.js new file mode 100644 index 0000000..22d2149 --- /dev/null +++ b/server/dist/routes/api/get/getHome.js @@ -0,0 +1,27 @@ +"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; diff --git a/server/dist/routes/api/get/getQueue.js b/server/dist/routes/api/get/getQueue.js new file mode 100644 index 0000000..d6ace3e --- /dev/null +++ b/server/dist/routes/api/get/getQueue.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const main_1 = require("../../../main"); +const path = '/getQueue'; +// let homeCache: any +const handler = (_, res) => { + const result = { + queue: main_1.queue, + order: main_1.queueOrder + }; + if (main_1.currentJob) + result.currentItem = main_1.currentJob.downloadObject.getSlimmedDict(); + res.send(result); +}; +const apiHandler = { path, handler }; +exports.default = apiHandler; diff --git a/server/dist/routes/api/get/sample.js b/server/dist/routes/api/get/getSettings.js similarity index 53% rename from server/dist/routes/api/get/sample.js rename to server/dist/routes/api/get/getSettings.js index 07d1f72..274005b 100644 --- a/server/dist/routes/api/get/sample.js +++ b/server/dist/routes/api/get/getSettings.js @@ -1,8 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const path = '/sample'; +const main_1 = require("../../../main"); +const path = '/getSettings'; const handler = (_, res) => { - res.send('Mandi'); + res.send({ settings: main_1.settings, defaultSettings: main_1.defaultSettings }); }; const apiHandler = { path, handler }; exports.default = apiHandler; diff --git a/server/dist/routes/api/get/getTracklist.js b/server/dist/routes/api/get/getTracklist.js new file mode 100644 index 0000000..4f94842 --- /dev/null +++ b/server/dist/routes/api/get/getTracklist.js @@ -0,0 +1,53 @@ +"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; + } + 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; diff --git a/server/dist/routes/api/get/getUserAlbums.js b/server/dist/routes/api/get/getUserAlbums.js new file mode 100644 index 0000000..791e514 --- /dev/null +++ b/server/dist/routes/api/get/getUserAlbums.js @@ -0,0 +1,37 @@ +"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; diff --git a/server/dist/routes/api/get/getUserArtists.js b/server/dist/routes/api/get/getUserArtists.js new file mode 100644 index 0000000..ce12e74 --- /dev/null +++ b/server/dist/routes/api/get/getUserArtists.js @@ -0,0 +1,37 @@ +"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; diff --git a/server/dist/routes/api/get/getUserFavorites.js b/server/dist/routes/api/get/getUserFavorites.js new file mode 100644 index 0000000..6463548 --- /dev/null +++ b/server/dist/routes/api/get/getUserFavorites.js @@ -0,0 +1,47 @@ +"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; diff --git a/server/dist/routes/api/get/getUserPlaylists.js b/server/dist/routes/api/get/getUserPlaylists.js new file mode 100644 index 0000000..e708edc --- /dev/null +++ b/server/dist/routes/api/get/getUserPlaylists.js @@ -0,0 +1,37 @@ +"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; diff --git a/server/dist/routes/api/get/getUserSpotifyPlaylists.js b/server/dist/routes/api/get/getUserSpotifyPlaylists.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/get/getUserSpotifyPlaylists.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/get/getUserTracks.js b/server/dist/routes/api/get/getUserTracks.js new file mode 100644 index 0000000..ea42f43 --- /dev/null +++ b/server/dist/routes/api/get/getUserTracks.js @@ -0,0 +1,37 @@ +"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; diff --git a/server/dist/routes/api/get/index.js b/server/dist/routes/api/get/index.js index 6c4c2de..dbbd615 100644 --- a/server/dist/routes/api/get/index.js +++ b/server/dist/routes/api/get/index.js @@ -3,5 +3,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const sample_1 = __importDefault(require("./sample")); -exports.default = [sample_1.default]; +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 getUserFavorites_1 = __importDefault(require("./getUserFavorites")); +const getQueue_1 = __importDefault(require("./getQueue")); +exports.default = [ + albumSearch_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, + getUserFavorites_1.default, + getQueue_1.default +]; diff --git a/server/dist/routes/api/get/mainSearch.js b/server/dist/routes/api/get/mainSearch.js new file mode 100644 index 0000000..1a12e62 --- /dev/null +++ b/server/dist/routes/api/get/mainSearch.js @@ -0,0 +1,64 @@ +"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}/156x156-000000-80-0-0.jpg`; + 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}/156x156-000000-80-0-0.jpg`; + 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}/156x156-000000-80-0-0.jpg`; + 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/156x156-000000-80-0-0.jpg'; + break; + } + results.TOP_RESULT = [topResult]; + } + results.ORDER = order; + res.send(results); +}); +const apiHandler = { path, handler }; +exports.default = apiHandler; diff --git a/server/dist/routes/api/get/newReleases.js b/server/dist/routes/api/get/newReleases.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/get/newReleases.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/get/search.js b/server/dist/routes/api/get/search.js new file mode 100644 index 0000000..6fba6cd --- /dev/null +++ b/server/dist/routes/api/get/search.js @@ -0,0 +1,52 @@ +"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; diff --git a/server/dist/routes/api/post/addToQueue.js b/server/dist/routes/api/post/addToQueue.js new file mode 100644 index 0000000..d649fd5 --- /dev/null +++ b/server/dist/routes/api/post/addToQueue.js @@ -0,0 +1,48 @@ +"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(';'); + let bitrate = req.query.bitrate; + if (bitrate === 'null') + bitrate = main_1.settings.maxBitrate; + let obj; + try { + obj = yield main_1.addToQueue(dz, url, bitrate); + } + catch (e) { + switch (e.name) { + case 'AlreadyInQueue': + res.send({ result: false, errid: e.name, data: { url, bitrate, obj: e.item } }); + main_1.listener.send('alreadyInQueue', e.item); + break; + 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; diff --git a/server/dist/routes/api/post/cancelAllDownloads.js b/server/dist/routes/api/post/cancelAllDownloads.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/post/cancelAllDownloads.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/post/index.js b/server/dist/routes/api/post/index.js index 72df421..4b86426 100644 --- a/server/dist/routes/api/post/index.js +++ b/server/dist/routes/api/post/index.js @@ -1,3 +1,9 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = []; +const login_arl_1 = __importDefault(require("./login-arl")); +const addToQueue_1 = __importDefault(require("./addToQueue")); +const loginWithCredentials_1 = __importDefault(require("./loginWithCredentials")); +exports.default = [login_arl_1.default, addToQueue_1.default, loginWithCredentials_1.default]; diff --git a/server/dist/routes/api/post/login-arl.js b/server/dist/routes/api/post/login-arl.js new file mode 100644 index 0000000..e3f17b7 --- /dev/null +++ b/server/dist/routes/api/post/login-arl.js @@ -0,0 +1,62 @@ +"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, next) => __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) { + res.status(400).send(); + return next(); + } + if (!req.query.arl) { + res.status(400).send(); + return next(); + } + 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); + } + console.log(response); + const returnValue = { status: response, arl: req.query.arl, user: dz.current_user }; + res.status(200).send(returnValue); + main_1.startQueue(dz); + next(); +}); +const apiHandler = { path, handler }; +exports.default = apiHandler; diff --git a/server/dist/routes/api/post/login-arl.spec.js b/server/dist/routes/api/post/login-arl.spec.js new file mode 100644 index 0000000..99d2059 --- /dev/null +++ b/server/dist/routes/api/post/login-arl.spec.js @@ -0,0 +1,41 @@ +"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 utils_1 = require("../../../../tests/utils"); +describe('login-arl requests', () => { + it('should respond 200 to calls with arl', () => __awaiter(void 0, void 0, void 0, function* () { + const responseStatusCollector = []; + const batchCalls = ['/api/login-arl/?arl=abcdef1234']; + for (const uri of batchCalls) { + responseStatusCollector.push((yield utils_1.appSendPost(uri)).status); + } + expect(responseStatusCollector).toMatchObject(new Array(batchCalls.length).fill(200)); + expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(200)); + })); + it('should respond 400 to calls without arl', () => __awaiter(void 0, void 0, void 0, function* () { + const responseStatusCollector = []; + const batchCalls = ['/api/login-arl/', '/api/login-arl/?dummy=test', '/api/login-arl/?email=aaa@aa.com']; + for (const uri of batchCalls) { + responseStatusCollector.push((yield utils_1.appSendPost(uri)).status); + } + expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(400)); + })); + it('should login using ARL', () => __awaiter(void 0, void 0, void 0, function* () { + const response = yield utils_1.appSendPost(`/api/login-arl/?arl=${process.env.DEEZER_ARL}`); + expect(response.status).toBe(200); + expect(response.body).toBe(true); + })); + it('should not login using wrong ARL', () => __awaiter(void 0, void 0, void 0, function* () { + const response = yield utils_1.appSendPost(`/api/login-arl/?arl=abcdef1234`); + expect(response.status).toBe(200); + expect(response.body).toBe(false); + })); +}); diff --git a/server/dist/routes/api/post/loginWithCredentials.js b/server/dist/routes/api/post/loginWithCredentials.js new file mode 100644 index 0000000..e811f99 --- /dev/null +++ b/server/dist/routes/api/post/loginWithCredentials.js @@ -0,0 +1,27 @@ +"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 { username, password } = req.body; + let accessToken = req.body.accessToken; + if (!accessToken) { + const accessToken = yield main_1.getAccessToken(username, password); + console.log({ accessToken }); + } + let arl; + if (accessToken) + arl = main_1.getArlFromAccessToken(accessToken); + res.send({ accessToken, arl }); +}); +const apiHandler = { path, handler }; +exports.default = apiHandler; diff --git a/server/dist/routes/api/post/logout.js b/server/dist/routes/api/post/logout.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/post/logout.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/post/openDownloadsFolder.js b/server/dist/routes/api/post/openDownloadsFolder.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/post/openDownloadsFolder.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/post/removeFinishedDownloads.js b/server/dist/routes/api/post/removeFinishedDownloads.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/post/removeFinishedDownloads.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/post/removeFromQueue.js b/server/dist/routes/api/post/removeFromQueue.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/routes/api/post/removeFromQueue.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/routes/api/register.js b/server/dist/routes/api/register.js index 54c0d23..42e96e3 100644 --- a/server/dist/routes/api/register.js +++ b/server/dist/routes/api/register.js @@ -30,9 +30,13 @@ const methods = [ function registerApis(app) { methods.forEach(({ method, endpoints }) => { endpoints.forEach(endpoint => { - // @ts-ignore + // @ts-expect-error app[method](prependApiPath(endpoint.path), endpoint.handler); }); }); + // Fallback, for SPA mode + app.get('*', (_, res) => { + res.redirect('/'); + }); } exports.registerApis = registerApis; diff --git a/server/dist/routes/index.js b/server/dist/routes/index.js index befaec0..882bcc3 100644 --- a/server/dist/routes/index.js +++ b/server/dist/routes/index.js @@ -4,6 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (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(); /** * GET home page @@ -11,6 +14,32 @@ const router = express_1.default.Router(); * @since 0.0.0 */ router.get('/', (_, res) => { - res.render('index', { title: 'Express' }); + res.render('index', { title: 'deemix' }); +}); +router.get('/connect', (req, res) => { + 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 result = { + update: { + currentCommit: 'testing', + latestCommit: 'testing', + updateAvailable: false, + deemixVersion: '3.0_beta' + }, + autologin: !dz.logged_in, + currentUser: dz.current_user, + deezerNotAvailable: false + }; + if (Object.keys(main_1.queue).length > 0) { + result.queue = { + queue: main_1.queue, + queueOrder: main_1.queueOrder + }; + if (main_1.currentJob && main_1.currentJob !== true) { + result.queue.current = main_1.currentJob.downloadObject.getSlimmedDict(); + } + } + res.send(result); }); exports.default = router; diff --git a/server/dist/routes/index.spec.js b/server/dist/routes/index.spec.js new file mode 100644 index 0000000..0cd03df --- /dev/null +++ b/server/dist/routes/index.spec.js @@ -0,0 +1,39 @@ +"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 supertest_1 = __importDefault(require("supertest")); +const app_1 = require("../app"); +describe('root path requests', () => { + it('responds 200 to the GET method', () => __awaiter(void 0, void 0, void 0, function* () { + const result = yield supertest_1.default(app_1.app).get('/').send(); + expect(result.status).toBe(200); + })); + it('responds 404 to the POST method', () => __awaiter(void 0, void 0, void 0, function* () { + const result = yield supertest_1.default(app_1.app).post('/').send(); + expect(result.status).toBe(404); + })); + it('responds 404 to the PATCH method', () => __awaiter(void 0, void 0, void 0, function* () { + const result = yield supertest_1.default(app_1.app).patch('/').send(); + expect(result.status).toBe(404); + })); + it('responds 404 to the DELETE method', () => __awaiter(void 0, void 0, void 0, function* () { + const result = yield supertest_1.default(app_1.app).delete('/').send(); + expect(result.status).toBe(404); + })); + it('redirects to root when a non existing server route is requested', () => __awaiter(void 0, void 0, void 0, function* () { + const result = yield supertest_1.default(app_1.app).get('/settings').send(); + expect(result.header.location).toBe('/'); + expect(result.status).toBe(302); + })); +}); diff --git a/server/dist/routes/users.js b/server/dist/routes/users.js deleted file mode 100644 index 29ccfbb..0000000 --- a/server/dist/routes/users.js +++ /dev/null @@ -1,16 +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 express_1 = __importDefault(require("express")); -const router = express_1.default.Router(); -/** - * GET users listing. - * - * @since 0.0.0 - */ -router.get('/', (_, res) => { - res.send('respond with a resource'); -}); -exports.default = router; diff --git a/server/dist/websocket/index.js b/server/dist/websocket/index.js new file mode 100644 index 0000000..07fa5c7 --- /dev/null +++ b/server/dist/websocket/index.js @@ -0,0 +1,30 @@ +"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; diff --git a/server/dist/websocket/modules/analyzeLink.js b/server/dist/websocket/modules/analyzeLink.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/analyzeLink.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/applogin.js b/server/dist/websocket/modules/applogin.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/applogin.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/cancelAllDownloads.js b/server/dist/websocket/modules/cancelAllDownloads.js new file mode 100644 index 0000000..5831166 --- /dev/null +++ b/server/dist/websocket/modules/cancelAllDownloads.js @@ -0,0 +1,10 @@ +"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 }; diff --git a/server/dist/websocket/modules/changeAccount.js b/server/dist/websocket/modules/changeAccount.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/changeAccount.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/index.js b/server/dist/websocket/modules/index.js new file mode 100644 index 0000000..84e869f --- /dev/null +++ b/server/dist/websocket/modules/index.js @@ -0,0 +1,10 @@ +"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]; diff --git a/server/dist/websocket/modules/logout.js b/server/dist/websocket/modules/logout.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/logout.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/openDownloadsFolder.js b/server/dist/websocket/modules/openDownloadsFolder.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/openDownloadsFolder.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/queueRestored.js b/server/dist/websocket/modules/queueRestored.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/queueRestored.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/dist/websocket/modules/removeFinishedDownloads.js b/server/dist/websocket/modules/removeFinishedDownloads.js new file mode 100644 index 0000000..d0b4f3b --- /dev/null +++ b/server/dist/websocket/modules/removeFinishedDownloads.js @@ -0,0 +1,10 @@ +"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 }; diff --git a/server/dist/websocket/modules/removeFromQueue.js b/server/dist/websocket/modules/removeFromQueue.js new file mode 100644 index 0000000..b1993b5 --- /dev/null +++ b/server/dist/websocket/modules/removeFromQueue.js @@ -0,0 +1,10 @@ +"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 }; diff --git a/server/dist/websocket/modules/saveSettings.js b/server/dist/websocket/modules/saveSettings.js new file mode 100644 index 0000000..66fa56b --- /dev/null +++ b/server/dist/websocket/modules/saveSettings.js @@ -0,0 +1,12 @@ +"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); + errors_1.consoleInfo('Settings saved'); + main_1.listener.send('updateSettings', { settings, spotifySettings }); +}; +exports.default = { eventName, cb }; diff --git a/server/dist/websocket/modules/selectDownloadFolder.js b/server/dist/websocket/modules/selectDownloadFolder.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/server/dist/websocket/modules/selectDownloadFolder.js @@ -0,0 +1 @@ +"use strict"; diff --git a/server/src/helpers/paths.ts b/server/src/helpers/paths.ts index 87d1218..ff4ef56 100644 --- a/server/src/helpers/paths.ts +++ b/server/src/helpers/paths.ts @@ -1,4 +1,4 @@ import path from 'path' -export const ROOT_DIR = path.resolve('../') +export const ROOT_DIR = path.resolve(path.join(__dirname, '..', '..', '..')) export const WEBUI_DIR = path.join(ROOT_DIR, 'webui', 'public') diff --git a/server/tsconfig.json b/server/tsconfig.json index f13991d..f81fcb3 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -67,5 +67,10 @@ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } + }, + "exclude": [ + "node_modules", + "**/*.spec.ts", + "tests/**" + ] }