Major code rework
This commit is contained in:
parent
5d29424c3a
commit
87164f0644
8
index.js
8
index.js
@ -10,13 +10,15 @@ const argv = yargs(hideBin(process.argv)).options({
|
|||||||
host: { type: 'string', default: '127.0.0.1' },
|
host: { type: 'string', default: '127.0.0.1' },
|
||||||
dev: { type: 'boolean', default: false}
|
dev: { type: 'boolean', default: false}
|
||||||
}).argv
|
}).argv
|
||||||
const server = require('./server/dist/app.js')
|
const { DeemixServer }= require('./server/dist/app.js')
|
||||||
|
|
||||||
const PORT = process.env.DEEMIX_SERVER_PORT || argv.port
|
const PORT = process.env.DEEMIX_SERVER_PORT || argv.port
|
||||||
|
|
||||||
process.env.DEEMIX_SERVER_PORT = PORT
|
process.env.DEEMIX_SERVER_PORT = PORT
|
||||||
process.env.DEEMIX_HOST = argv.host
|
process.env.DEEMIX_HOST = argv.host
|
||||||
|
|
||||||
|
const server = new DeemixServer(argv.host, PORT)
|
||||||
|
server.init()
|
||||||
|
|
||||||
let win
|
let win
|
||||||
const windowState = new WindowStateManager('mainWindow', {
|
const windowState = new WindowStateManager('mainWindow', {
|
||||||
defaultWidth: 800,
|
defaultWidth: 800,
|
||||||
@ -91,7 +93,7 @@ app.on('window-all-closed', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('openDownloadsFolder', (event)=>{
|
ipcMain.on('openDownloadsFolder', (event)=>{
|
||||||
const { downloadLocation } = server.getSettings().settings
|
const { downloadLocation } = server.deemixApp.getSettings().settings
|
||||||
shell.openPath(downloadLocation)
|
shell.openPath(downloadLocation)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,2 +1 @@
|
|||||||
bin/www
|
|
||||||
dist/
|
dist/
|
||||||
|
2
server/dist/app.js
vendored
2
server/dist/app.js
vendored
File diff suppressed because one or more lines are too long
426
server/dist/app.js.LICENSE.txt
vendored
426
server/dist/app.js.LICENSE.txt
vendored
@ -1,426 +0,0 @@
|
|||||||
/*!
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
|
|
||||||
|
|
||||||
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
|
@ -1,67 +1,374 @@
|
|||||||
import http from 'http'
|
import fs from 'fs'
|
||||||
import express, { Application } from 'express'
|
import { sep } from 'path'
|
||||||
import { Server as WsServer } from 'ws'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import yargs from 'yargs'
|
// @ts-expect-error
|
||||||
import initDebug from 'debug'
|
import deemix from 'deemix'
|
||||||
import { hideBin } from 'yargs/helpers'
|
import got from 'got'
|
||||||
|
import { Settings, Listener } from './types'
|
||||||
|
import { NotLoggedIn } from './helpers/errors'
|
||||||
|
|
||||||
import { registerMiddlewares } from './middlewares'
|
import { GUI_PACKAGE } from './helpers/paths'
|
||||||
|
|
||||||
import indexRouter from './routes'
|
// Types
|
||||||
|
const Downloader = deemix.downloader.Downloader
|
||||||
|
const { Single, Collection, Convertable } = deemix.types.downloadObjects
|
||||||
|
|
||||||
import { normalizePort } from './helpers/port'
|
// Functions
|
||||||
import { getErrorCb, getListeningCb } from './helpers/server-callbacks'
|
export const getAccessToken = deemix.utils.deezer.getAccessToken
|
||||||
import { registerApis } from './routes/api/register'
|
export const getArlFromAccessToken = deemix.utils.deezer.getArlFromAccessToken
|
||||||
import { registerWebsocket } from './websocket'
|
|
||||||
import type { Arguments } from './types'
|
|
||||||
import { consoleInfo } from './helpers/errors'
|
|
||||||
|
|
||||||
export { getSettings } from './main'
|
// Constants
|
||||||
|
export const configFolder: string = deemix.utils.localpaths.getConfigFolder()
|
||||||
|
export const defaultSettings: Settings = deemix.settings.DEFAULTS
|
||||||
|
export const deemixVersion = require('../node_modules/deemix/package.json').version
|
||||||
|
const currentVersionTemp = JSON.parse(String(fs.readFileSync(GUI_PACKAGE))).version
|
||||||
|
export const currentVersion = currentVersionTemp === '0.0.0' ? 'continuous' : currentVersionTemp
|
||||||
|
|
||||||
// TODO: Remove type assertion while keeping correct types
|
export const sessionDZ: any = {}
|
||||||
const argv = yargs(hideBin(process.argv)).options({
|
|
||||||
port: { type: 'string', default: '6595' },
|
|
||||||
host: { type: 'string', default: '127.0.0.1' }
|
|
||||||
}).argv as Arguments
|
|
||||||
|
|
||||||
const DEEMIX_SERVER_PORT = normalizePort(process.env.DEEMIX_SERVER_PORT ?? argv.port)
|
export class DeemixApp {
|
||||||
const DEEMIX_HOST = process.env.DEEMIX_HOST ?? argv.host
|
queueOrder: string[]
|
||||||
|
queue: any
|
||||||
|
currentJob: any
|
||||||
|
|
||||||
const debug = initDebug('deemix-gui:server')
|
deezerAvailable: boolean | null
|
||||||
export const wss = new WsServer({ noServer: true })
|
latestVersion: string | null
|
||||||
const app: Application = express()
|
|
||||||
const server = http.createServer(app)
|
|
||||||
|
|
||||||
/* === Middlewares === */
|
plugins: any
|
||||||
registerMiddlewares(app)
|
settings: any
|
||||||
|
|
||||||
/* === Routes === */
|
listener: Listener
|
||||||
app.use('/', indexRouter)
|
|
||||||
|
|
||||||
/* === APIs === */
|
constructor(listener: Listener) {
|
||||||
registerApis(app)
|
this.settings = deemix.settings.load(configFolder)
|
||||||
|
|
||||||
/* === Config === */
|
this.queueOrder = []
|
||||||
app.set('port', DEEMIX_SERVER_PORT)
|
this.queue = {}
|
||||||
|
this.currentJob = null
|
||||||
|
|
||||||
/* === Server port === */
|
this.plugins = {
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
// eslint-disable-next-line new-cap
|
||||||
server.listen({ port: DEEMIX_SERVER_PORT, host: DEEMIX_HOST })
|
spotify: new deemix.plugins.spotify()
|
||||||
|
}
|
||||||
|
this.deezerAvailable = null
|
||||||
|
this.latestVersion = null
|
||||||
|
this.listener = listener
|
||||||
|
|
||||||
|
this.plugins.spotify.setup()
|
||||||
|
this.restoreQueueFromDisk()
|
||||||
|
}
|
||||||
|
|
||||||
|
async isDeezerAvailable(): Promise<boolean> {
|
||||||
|
if (this.deezerAvailable === null) {
|
||||||
|
let response
|
||||||
|
try {
|
||||||
|
response = await got.get('https://www.deezer.com/', {
|
||||||
|
headers: { Cookie: 'dz_lang=en; Domain=deezer.com; Path=/; Secure; hostOnly=false;' },
|
||||||
|
https: {
|
||||||
|
rejectUnauthorized: false
|
||||||
|
},
|
||||||
|
retry: 5
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.trace(e)
|
||||||
|
this.deezerAvailable = false
|
||||||
|
return this.deezerAvailable
|
||||||
|
}
|
||||||
|
const title = (response.body.match(/<title[^>]*>([^<]+)<\/title>/)![1] || '').trim()
|
||||||
|
this.deezerAvailable = title !== 'Deezer will soon be available in your country.'
|
||||||
|
}
|
||||||
|
return this.deezerAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestVersion(force = false): Promise<string | null> {
|
||||||
|
if ((this.latestVersion === null || force) && !this.settings.disableUpdateCheck) {
|
||||||
|
let response
|
||||||
|
try {
|
||||||
|
response = await got.get('https://deemix.app/gui/latest', {
|
||||||
|
https: {
|
||||||
|
rejectUnauthorized: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.trace(e)
|
||||||
|
this.latestVersion = 'NotFound'
|
||||||
|
return this.latestVersion
|
||||||
|
}
|
||||||
|
this.latestVersion = response.body.trim()
|
||||||
|
}
|
||||||
|
return this.latestVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
parseVersion(version: string | null): any {
|
||||||
|
if (version === null || version === 'continuous' || version === 'NotFound') return null
|
||||||
|
try {
|
||||||
|
const matchResult = version.match(/(\d+)\.(\d+)\.(\d+)-r(\d)+\.(.+)/) || []
|
||||||
|
return {
|
||||||
|
year: parseInt(matchResult[1]),
|
||||||
|
month: parseInt(matchResult[2]),
|
||||||
|
day: parseInt(matchResult[3]),
|
||||||
|
revision: parseInt(matchResult[4]),
|
||||||
|
commit: matchResult[5] || ''
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.trace(e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isUpdateAvailable(): boolean {
|
||||||
|
const currentVersionObj: any = this.parseVersion(currentVersion)
|
||||||
|
const latestVersionObj: any = this.parseVersion(this.latestVersion)
|
||||||
|
if (currentVersionObj === null || latestVersionObj === null) return false
|
||||||
|
if (latestVersionObj.year > currentVersionObj.year) return true
|
||||||
|
if (latestVersionObj.month > currentVersionObj.month) return true
|
||||||
|
if (latestVersionObj.day > currentVersionObj.day) return true
|
||||||
|
if (latestVersionObj.revision > currentVersionObj.revision) return true
|
||||||
|
if (latestVersionObj.commit !== currentVersionObj.commit) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettings(): any {
|
||||||
|
return { settings: this.settings, defaultSettings, spotifySettings: this.plugins.spotify.getSettings() }
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSettings(newSettings: any, newSpotifySettings: any) {
|
||||||
|
newSettings.executeCommand = this.settings.executeCommand
|
||||||
|
deemix.settings.save(newSettings, configFolder)
|
||||||
|
this.settings = newSettings
|
||||||
|
this.plugins.spotify.saveSettings(newSpotifySettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
getQueue() {
|
||||||
|
const result: any = {
|
||||||
|
queue: this.queue,
|
||||||
|
queueOrder: this.queueOrder
|
||||||
|
}
|
||||||
|
if (this.currentJob && this.currentJob !== true) {
|
||||||
|
result.current = this.currentJob.downloadObject.getSlimmedDict()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async addToQueue(dz: any, url: string[], bitrate: number) {
|
||||||
|
if (!dz.logged_in) throw new NotLoggedIn()
|
||||||
|
|
||||||
|
let downloadObjs: any[] = []
|
||||||
|
const downloadErrors: any[] = []
|
||||||
|
let link: string = ''
|
||||||
|
const requestUUID = uuidv4()
|
||||||
|
|
||||||
|
if (url.length > 1) {
|
||||||
|
this.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 = await deemix.generateDownloadObject(dz, link, bitrate, this.plugins, this.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: any) => {
|
||||||
|
if (!e.errid) console.trace(e)
|
||||||
|
this.listener.send('queueError', { link: e.link, error: e.message, errid: e.errid })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.length > 1) {
|
||||||
|
this.listener.send('finishGeneratingItems', { uuid: requestUUID, total: downloadObjs.length })
|
||||||
|
}
|
||||||
|
|
||||||
|
const slimmedObjects: any[] = []
|
||||||
|
|
||||||
|
downloadObjs.forEach((downloadObj: any, pos: number) => {
|
||||||
|
// Check if element is already in queue
|
||||||
|
if (Object.keys(this.queue).includes(downloadObj.uuid)) {
|
||||||
|
this.listener.send('alreadyInQueue', downloadObj.getEssentialDict())
|
||||||
|
delete downloadObjs[pos]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save queue status when adding something to the queue
|
||||||
|
if (!fs.existsSync(configFolder + 'queue')) fs.mkdirSync(configFolder + 'queue')
|
||||||
|
|
||||||
|
this.queueOrder.push(downloadObj.uuid)
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(this.queueOrder))
|
||||||
|
this.queue[downloadObj.uuid] = downloadObj.getEssentialDict()
|
||||||
|
this.queue[downloadObj.uuid].status = 'inQueue'
|
||||||
|
|
||||||
|
const savedObject = downloadObj.toDict()
|
||||||
|
savedObject.status = 'inQueue'
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}${downloadObj.uuid}.json`, JSON.stringify(savedObject))
|
||||||
|
|
||||||
|
slimmedObjects.push(downloadObj.getSlimmedDict())
|
||||||
|
})
|
||||||
|
const isSingleObject = downloadObjs.length === 1
|
||||||
|
if (isSingleObject) this.listener.send('addedToQueue', downloadObjs[0].getSlimmedDict())
|
||||||
|
else this.listener.send('addedToQueue', slimmedObjects)
|
||||||
|
|
||||||
|
this.startQueue(dz)
|
||||||
|
return slimmedObjects
|
||||||
|
}
|
||||||
|
|
||||||
|
async startQueue(dz: any): Promise<any> {
|
||||||
|
do {
|
||||||
|
if (this.currentJob !== null || this.queueOrder.length === 0) {
|
||||||
|
// Should not start another download
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
this.currentJob = true // lock currentJob
|
||||||
|
|
||||||
|
let currentUUID: string
|
||||||
|
do {
|
||||||
|
currentUUID = this.queueOrder.shift() || ''
|
||||||
|
} while (this.queue[currentUUID] === undefined && this.queueOrder.length)
|
||||||
|
this.queue[currentUUID].status = 'downloading'
|
||||||
|
const currentItem: any = JSON.parse(fs.readFileSync(configFolder + `queue${sep}${currentUUID}.json`).toString())
|
||||||
|
let downloadObject: any
|
||||||
|
switch (currentItem.__type__) {
|
||||||
|
case 'Single':
|
||||||
|
downloadObject = new Single(currentItem)
|
||||||
|
break
|
||||||
|
case 'Collection':
|
||||||
|
downloadObject = new Collection(currentItem)
|
||||||
|
break
|
||||||
|
case 'Convertable':
|
||||||
|
downloadObject = new Convertable(currentItem)
|
||||||
|
downloadObject = await this.plugins[downloadObject.plugin].convert(
|
||||||
|
dz,
|
||||||
|
downloadObject,
|
||||||
|
this.settings,
|
||||||
|
this.listener
|
||||||
|
)
|
||||||
|
fs.writeFileSync(
|
||||||
|
configFolder + `queue${sep}${downloadObject.uuid}.json`,
|
||||||
|
JSON.stringify({ ...downloadObject.toDict(), status: 'inQueue' })
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.currentJob = new Downloader(dz, downloadObject, this.settings, this.listener)
|
||||||
|
this.listener.send('startDownload', currentUUID)
|
||||||
|
await this.currentJob.start()
|
||||||
|
|
||||||
|
if (!downloadObject.isCanceled) {
|
||||||
|
// Set status
|
||||||
|
if (downloadObject.failed === downloadObject.size && downloadObject.size !== 0) {
|
||||||
|
this.queue[currentUUID].status = 'failed'
|
||||||
|
} else if (downloadObject.failed > 0) {
|
||||||
|
this.queue[currentUUID].status = 'withErrors'
|
||||||
|
} else {
|
||||||
|
this.queue[currentUUID].status = 'completed'
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedObject = downloadObject.getSlimmedDict()
|
||||||
|
savedObject.status = this.queue[currentUUID].status
|
||||||
|
|
||||||
|
// Save queue status
|
||||||
|
this.queue[currentUUID] = savedObject
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}${currentUUID}.json`, JSON.stringify(savedObject))
|
||||||
|
}
|
||||||
|
console.log(this.queueOrder)
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(this.queueOrder))
|
||||||
|
|
||||||
|
this.currentJob = null
|
||||||
|
} while (this.queueOrder.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelDownload(uuid: string) {
|
||||||
|
if (Object.keys(this.queue).includes(uuid)) {
|
||||||
|
switch (this.queue[uuid].status) {
|
||||||
|
case 'downloading':
|
||||||
|
this.currentJob.downloadObject.isCanceled = true
|
||||||
|
this.listener.send('cancellingCurrentItem', uuid)
|
||||||
|
break
|
||||||
|
case 'inQueue':
|
||||||
|
this.queueOrder.splice(this.queueOrder.indexOf(uuid), 1)
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(this.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
|
||||||
|
this.listener.send('removedFromQueue', uuid)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fs.unlinkSync(configFolder + `queue${sep}${uuid}.json`)
|
||||||
|
delete this.queue[uuid]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelAllDownloads() {
|
||||||
|
this.queueOrder = []
|
||||||
|
let currentItem: string | null = null
|
||||||
|
Object.values(this.queue).forEach((downloadObject: any) => {
|
||||||
|
if (downloadObject.status === 'downloading') {
|
||||||
|
this.currentJob.downloadObject.isCanceled = true
|
||||||
|
this.listener.send('cancellingCurrentItem', downloadObject.uuid)
|
||||||
|
currentItem = downloadObject.uuid
|
||||||
|
}
|
||||||
|
fs.unlinkSync(configFolder + `queue${sep}${downloadObject.uuid}.json`)
|
||||||
|
delete this.queue[downloadObject.uuid]
|
||||||
|
})
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(this.queueOrder))
|
||||||
|
this.listener.send('removedAllDownloads', currentItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCompletedDownloads() {
|
||||||
|
Object.values(this.queue).forEach((downloadObject: any) => {
|
||||||
|
if (downloadObject.status === 'completed') {
|
||||||
|
fs.unlinkSync(configFolder + `queue${sep}${downloadObject.uuid}.json`)
|
||||||
|
delete this.queue[downloadObject.uuid]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.listener.send('removedFinishedDownloads')
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreQueueFromDisk() {
|
||||||
|
if (!fs.existsSync(configFolder + 'queue')) fs.mkdirSync(configFolder + 'queue')
|
||||||
|
const allItems: string[] = fs.readdirSync(configFolder + 'queue')
|
||||||
|
allItems.forEach((filename: string) => {
|
||||||
|
if (filename === 'order.json') {
|
||||||
|
try {
|
||||||
|
this.queueOrder = JSON.parse(fs.readFileSync(configFolder + `queue${sep}order.json`).toString())
|
||||||
|
} catch {
|
||||||
|
this.queueOrder = []
|
||||||
|
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(this.queueOrder))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let currentItem: any
|
||||||
|
try {
|
||||||
|
currentItem = JSON.parse(fs.readFileSync(configFolder + `queue${sep}${filename}`).toString())
|
||||||
|
} catch {
|
||||||
|
fs.unlinkSync(configFolder + `queue${sep}${filename}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentItem.status === 'inQueue') {
|
||||||
|
let downloadObject: any
|
||||||
|
switch (currentItem.__type__) {
|
||||||
|
case 'Single':
|
||||||
|
downloadObject = new Single(currentItem)
|
||||||
|
break
|
||||||
|
case 'Collection':
|
||||||
|
downloadObject = new Collection(currentItem)
|
||||||
|
break
|
||||||
|
case 'Convertable':
|
||||||
|
downloadObject = new Convertable(currentItem)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.queue[downloadObject.uuid] = downloadObject.getEssentialDict()
|
||||||
|
this.queue[downloadObject.uuid].status = 'inQueue'
|
||||||
|
} else {
|
||||||
|
this.queue[currentItem.uuid] = currentItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerWebsocket(wss)
|
|
||||||
|
|
||||||
/* === Server callbacks === */
|
|
||||||
app.on('mount', a => {
|
|
||||||
console.log(a)
|
|
||||||
})
|
|
||||||
server.on('connect', () => {
|
|
||||||
consoleInfo('Server connected')
|
|
||||||
})
|
|
||||||
server.on('upgrade', (request, socket, head) => {
|
|
||||||
wss.handleUpgrade(request, socket, head, socket => {
|
|
||||||
wss.emit('connection', socket, request)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
server.on('error', getErrorCb(DEEMIX_SERVER_PORT))
|
|
||||||
server.on('listening', getListeningCb(server, debug))
|
|
||||||
|
23
server/src/index.ts
Normal file
23
server/src/index.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import yargs from 'yargs'
|
||||||
|
import { hideBin } from 'yargs/helpers'
|
||||||
|
import type { Arguments } from './types'
|
||||||
|
|
||||||
|
import { DeemixServer } from './server'
|
||||||
|
|
||||||
|
const isModule = process.mainModule && process.mainModule.parent
|
||||||
|
|
||||||
|
if (!isModule) {
|
||||||
|
// TODO: Remove type assertion while keeping correct types
|
||||||
|
const argv = yargs(hideBin(process.argv)).options({
|
||||||
|
port: { type: 'string', default: '6595' },
|
||||||
|
host: { type: 'string', default: '127.0.0.1' }
|
||||||
|
}).argv as Arguments
|
||||||
|
|
||||||
|
const DEEMIX_SERVER_PORT = process.env.DEEMIX_SERVER_PORT ?? argv.port
|
||||||
|
const DEEMIX_HOST = process.env.DEEMIX_HOST ?? argv.host
|
||||||
|
|
||||||
|
const server = new DeemixServer(DEEMIX_HOST, DEEMIX_SERVER_PORT)
|
||||||
|
server.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DeemixServer }
|
@ -1,362 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import { sep } from 'path'
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
// @ts-expect-error
|
|
||||||
import deemix from 'deemix'
|
|
||||||
import WebSocket from 'ws'
|
|
||||||
import got from 'got'
|
|
||||||
import { wss } from './app'
|
|
||||||
import { Settings } from './types'
|
|
||||||
import { NotLoggedIn } from './helpers/errors'
|
|
||||||
|
|
||||||
import { GUI_PACKAGE } from './helpers/paths'
|
|
||||||
|
|
||||||
const Downloader = deemix.downloader.Downloader
|
|
||||||
const { Single, Collection, Convertable } = deemix.types.downloadObjects
|
|
||||||
export const defaultSettings: Settings = deemix.settings.DEFAULTS
|
|
||||||
export const configFolder: string = deemix.utils.localpaths.getConfigFolder()
|
|
||||||
export const sessionDZ: any = {}
|
|
||||||
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
|
|
||||||
const currentVersionTemp = JSON.parse(String(fs.readFileSync(GUI_PACKAGE))).version
|
|
||||||
export const currentVersion = currentVersionTemp === '0.0.0' ? 'continuous' : currentVersionTemp
|
|
||||||
let deezerAvailable: boolean | null = null
|
|
||||||
let latestVersion: string | null = null
|
|
||||||
|
|
||||||
export async function isDeezerAvailable(): Promise<boolean> {
|
|
||||||
if (deezerAvailable === null) {
|
|
||||||
let response
|
|
||||||
try {
|
|
||||||
response = await got.get('https://www.deezer.com/', {
|
|
||||||
headers: { Cookie: 'dz_lang=en; Domain=deezer.com; Path=/; Secure; hostOnly=false;' },
|
|
||||||
https: {
|
|
||||||
rejectUnauthorized: 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
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getLatestVersion(force = false): Promise<string | null> {
|
|
||||||
if ((latestVersion === null || force) && !settings.disableUpdateCheck) {
|
|
||||||
let response
|
|
||||||
try {
|
|
||||||
response = await got.get('https://deemix.app/gui/latest', {
|
|
||||||
https: {
|
|
||||||
rejectUnauthorized: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.trace(e)
|
|
||||||
latestVersion = 'NotFound'
|
|
||||||
return latestVersion
|
|
||||||
}
|
|
||||||
latestVersion = response.body.trim()
|
|
||||||
}
|
|
||||||
return latestVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseVersion(version: string | null): any {
|
|
||||||
if (version === null || version === 'continuous' || version === 'NotFound') return null
|
|
||||||
try {
|
|
||||||
const matchResult = version.match(/(\d+)\.(\d+)\.(\d+)-r(\d)+\.(.+)/) || []
|
|
||||||
return {
|
|
||||||
year: parseInt(matchResult[1]),
|
|
||||||
month: parseInt(matchResult[2]),
|
|
||||||
day: parseInt(matchResult[3]),
|
|
||||||
revision: parseInt(matchResult[4]),
|
|
||||||
commit: matchResult[5] || ''
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.trace(e)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isUpdateAvailable(): boolean {
|
|
||||||
const currentVersionObj: any = parseVersion(currentVersion)
|
|
||||||
const latestVersionObj: any = parseVersion(latestVersion)
|
|
||||||
if (currentVersionObj === null || latestVersionObj === null) return false
|
|
||||||
if (latestVersionObj.year > currentVersionObj.year) return true
|
|
||||||
if (latestVersionObj.month > currentVersionObj.month) return true
|
|
||||||
if (latestVersionObj.day > currentVersionObj.day) return true
|
|
||||||
if (latestVersionObj.revision > currentVersionObj.revision) return true
|
|
||||||
if (latestVersionObj.commit !== currentVersionObj.commit) return true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export const plugins: any = {
|
|
||||||
// eslint-disable-next-line new-cap
|
|
||||||
spotify: new deemix.plugins.spotify()
|
|
||||||
}
|
|
||||||
plugins.spotify.setup()
|
|
||||||
|
|
||||||
export const listener = {
|
|
||||||
send(key: string, data?: any) {
|
|
||||||
const logLine = deemix.utils.formatListener(key, data)
|
|
||||||
if (logLine) console.log(logLine)
|
|
||||||
if (['downloadInfo', 'downloadWarn'].includes(key)) return
|
|
||||||
wss.clients.forEach(client => {
|
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
|
||||||
client.send(JSON.stringify({ key, data }))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSettings(): any {
|
|
||||||
return { settings, defaultSettings, spotifySettings: plugins.spotify.getSettings() }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveSettings(newSettings: any, newSpotifySettings: any) {
|
|
||||||
newSettings.executeCommand = settings.executeCommand
|
|
||||||
deemix.settings.save(newSettings, configFolder)
|
|
||||||
settings = newSettings
|
|
||||||
plugins.spotify.saveSettings(newSpotifySettings)
|
|
||||||
}
|
|
||||||
|
|
||||||
let queueOrder: string[] = []
|
|
||||||
const queue: any = {}
|
|
||||||
let currentJob: any = null
|
|
||||||
|
|
||||||
restoreQueueFromDisk()
|
|
||||||
|
|
||||||
export function getQueue() {
|
|
||||||
const result: any = {
|
|
||||||
queue,
|
|
||||||
queueOrder
|
|
||||||
}
|
|
||||||
if (currentJob && currentJob !== true) {
|
|
||||||
result.current = currentJob.downloadObject.getSlimmedDict()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function addToQueue(dz: any, url: string[], bitrate: number) {
|
|
||||||
if (!dz.logged_in) throw new NotLoggedIn()
|
|
||||||
|
|
||||||
let downloadObjs: any[] = []
|
|
||||||
const downloadErrors: any[] = []
|
|
||||||
let link: string = ''
|
|
||||||
const requestUUID = uuidv4()
|
|
||||||
|
|
||||||
if (url.length > 1) {
|
|
||||||
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 = await deemix.generateDownloadObject(dz, link, bitrate, plugins, 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: any) => {
|
|
||||||
if (!e.errid) console.trace(e)
|
|
||||||
listener.send('queueError', { link: e.link, error: e.message, errid: e.errid })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.length > 1) {
|
|
||||||
listener.send('finishGeneratingItems', { uuid: requestUUID, total: downloadObjs.length })
|
|
||||||
}
|
|
||||||
|
|
||||||
const slimmedObjects: any[] = []
|
|
||||||
|
|
||||||
downloadObjs.forEach((downloadObj: any, pos: number) => {
|
|
||||||
// Check if element is already in queue
|
|
||||||
if (Object.keys(queue).includes(downloadObj.uuid)) {
|
|
||||||
listener.send('alreadyInQueue', downloadObj.getEssentialDict())
|
|
||||||
delete downloadObjs[pos]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save queue status when adding something to the queue
|
|
||||||
if (!fs.existsSync(configFolder + 'queue')) fs.mkdirSync(configFolder + 'queue')
|
|
||||||
|
|
||||||
queueOrder.push(downloadObj.uuid)
|
|
||||||
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(queueOrder))
|
|
||||||
queue[downloadObj.uuid] = downloadObj.getEssentialDict()
|
|
||||||
queue[downloadObj.uuid].status = 'inQueue'
|
|
||||||
|
|
||||||
const savedObject = downloadObj.toDict()
|
|
||||||
savedObject.status = 'inQueue'
|
|
||||||
fs.writeFileSync(configFolder + `queue${sep}${downloadObj.uuid}.json`, JSON.stringify(savedObject))
|
|
||||||
|
|
||||||
slimmedObjects.push(downloadObj.getSlimmedDict())
|
|
||||||
})
|
|
||||||
const isSingleObject = downloadObjs.length === 1
|
|
||||||
if (isSingleObject) listener.send('addedToQueue', downloadObjs[0].getSlimmedDict())
|
|
||||||
else listener.send('addedToQueue', slimmedObjects)
|
|
||||||
|
|
||||||
startQueue(dz)
|
|
||||||
return slimmedObjects
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function startQueue(dz: any): Promise<any> {
|
|
||||||
do {
|
|
||||||
if (currentJob !== null || queueOrder.length === 0) {
|
|
||||||
// Should not start another download
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
currentJob = true // lock currentJob
|
|
||||||
|
|
||||||
let currentUUID: string
|
|
||||||
do {
|
|
||||||
currentUUID = queueOrder.shift() || ''
|
|
||||||
} while (queue[currentUUID] === undefined && queueOrder.length)
|
|
||||||
queue[currentUUID].status = 'downloading'
|
|
||||||
const currentItem: any = JSON.parse(fs.readFileSync(configFolder + `queue${sep}${currentUUID}.json`).toString())
|
|
||||||
let downloadObject: any
|
|
||||||
switch (currentItem.__type__) {
|
|
||||||
case 'Single':
|
|
||||||
downloadObject = new Single(currentItem)
|
|
||||||
break
|
|
||||||
case 'Collection':
|
|
||||||
downloadObject = new Collection(currentItem)
|
|
||||||
break
|
|
||||||
case 'Convertable':
|
|
||||||
downloadObject = new Convertable(currentItem)
|
|
||||||
downloadObject = await plugins[downloadObject.plugin].convert(dz, downloadObject, settings, listener)
|
|
||||||
fs.writeFileSync(
|
|
||||||
configFolder + `queue${sep}${downloadObject.uuid}.json`,
|
|
||||||
JSON.stringify({ ...downloadObject.toDict(), status: 'inQueue' })
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
currentJob = new Downloader(dz, downloadObject, settings, listener)
|
|
||||||
listener.send('startDownload', currentUUID)
|
|
||||||
await currentJob.start()
|
|
||||||
|
|
||||||
if (!downloadObject.isCanceled) {
|
|
||||||
// Set status
|
|
||||||
if (downloadObject.failed === downloadObject.size && downloadObject.size !== 0) {
|
|
||||||
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.writeFileSync(configFolder + `queue${sep}${currentUUID}.json`, JSON.stringify(savedObject))
|
|
||||||
}
|
|
||||||
console.log(queueOrder)
|
|
||||||
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(queueOrder))
|
|
||||||
|
|
||||||
currentJob = null
|
|
||||||
} while (queueOrder.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelDownload(uuid: string) {
|
|
||||||
if (Object.keys(queue).includes(uuid)) {
|
|
||||||
switch (queue[uuid].status) {
|
|
||||||
case 'downloading':
|
|
||||||
currentJob.downloadObject.isCanceled = true
|
|
||||||
listener.send('cancellingCurrentItem', uuid)
|
|
||||||
break
|
|
||||||
case 'inQueue':
|
|
||||||
queueOrder.splice(queueOrder.indexOf(uuid), 1)
|
|
||||||
fs.writeFileSync(configFolder + `queue${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
|
|
||||||
listener.send('removedFromQueue', uuid)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fs.unlinkSync(configFolder + `queue${sep}${uuid}.json`)
|
|
||||||
delete queue[uuid]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelAllDownloads() {
|
|
||||||
queueOrder = []
|
|
||||||
let currentItem: string | null = null
|
|
||||||
Object.values(queue).forEach((downloadObject: any) => {
|
|
||||||
if (downloadObject.status === 'downloading') {
|
|
||||||
currentJob.downloadObject.isCanceled = true
|
|
||||||
listener.send('cancellingCurrentItem', downloadObject.uuid)
|
|
||||||
currentItem = downloadObject.uuid
|
|
||||||
}
|
|
||||||
fs.unlinkSync(configFolder + `queue${sep}${downloadObject.uuid}.json`)
|
|
||||||
delete queue[downloadObject.uuid]
|
|
||||||
})
|
|
||||||
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(queueOrder))
|
|
||||||
listener.send('removedAllDownloads', currentItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearCompletedDownloads() {
|
|
||||||
Object.values(queue).forEach((downloadObject: any) => {
|
|
||||||
if (downloadObject.status === 'completed') {
|
|
||||||
fs.unlinkSync(configFolder + `queue${sep}${downloadObject.uuid}.json`)
|
|
||||||
delete queue[downloadObject.uuid]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
listener.send('removedFinishedDownloads')
|
|
||||||
}
|
|
||||||
|
|
||||||
export function restoreQueueFromDisk() {
|
|
||||||
if (!fs.existsSync(configFolder + 'queue')) fs.mkdirSync(configFolder + 'queue')
|
|
||||||
const allItems: string[] = fs.readdirSync(configFolder + 'queue')
|
|
||||||
allItems.forEach((filename: string) => {
|
|
||||||
if (filename === 'order.json') {
|
|
||||||
try {
|
|
||||||
queueOrder = JSON.parse(fs.readFileSync(configFolder + `queue${sep}order.json`).toString())
|
|
||||||
} catch {
|
|
||||||
queueOrder = []
|
|
||||||
fs.writeFileSync(configFolder + `queue${sep}order.json`, JSON.stringify(queueOrder))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let currentItem: any
|
|
||||||
try {
|
|
||||||
currentItem = JSON.parse(fs.readFileSync(configFolder + `queue${sep}${filename}`).toString())
|
|
||||||
} catch {
|
|
||||||
fs.unlinkSync(configFolder + `queue${sep}${filename}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (currentItem.status === 'inQueue') {
|
|
||||||
let downloadObject: any
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ import type { RequestHandler } from 'express'
|
|||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
|
|
||||||
import type { ApiHandler } from '../../../types'
|
import type { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
export interface RawAlbumQuery {
|
export interface RawAlbumQuery {
|
||||||
term: string
|
term: string
|
||||||
|
@ -5,7 +5,7 @@ import deemix from 'deemix'
|
|||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
|
|
||||||
import type { ApiHandler, GetTrackResponse, GetAlbumResponse } from '../../../types'
|
import type { ApiHandler, GetTrackResponse, GetAlbumResponse } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
export interface AnalyzeQuery {
|
export interface AnalyzeQuery {
|
||||||
term?: string
|
term?: string
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { getLatestVersion, isUpdateAvailable } from '../../../main'
|
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/checkForUpdates'
|
const path: ApiHandler['path'] = '/checkForUpdates'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = async (_, res) => {
|
const handler: ApiHandler['handler'] = async (req, res) => {
|
||||||
const latestCommit = await getLatestVersion()
|
const deemix = req.app.get('deemix')
|
||||||
|
const latestCommit = await deemix.getLatestVersion()
|
||||||
res.send({
|
res.send({
|
||||||
latestCommit,
|
latestCommit,
|
||||||
updateAvailable: isUpdateAvailable()
|
updateAvailable: deemix.isUpdateAvailable()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { RequestHandler } from 'express'
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
import { isObjectEmpy } from '../../../helpers/primitive-checks'
|
import { isObjectEmpy } from '../../../helpers/primitive-checks'
|
||||||
import { BadRequestError, isBadRequestError, consoleError } from '../../../helpers/errors'
|
import { BadRequestError, isBadRequestError, consoleError } from '../../../helpers/errors'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getCharts'
|
const path: ApiHandler['path'] = '/getCharts'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getHome'
|
const path: ApiHandler['path'] = '/getHome'
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// import { Deezer } from 'deezer-js'
|
// import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { getQueue } from '../../../main'
|
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getQueue'
|
const path: ApiHandler['path'] = '/getQueue'
|
||||||
|
|
||||||
// let homeCache: any
|
// let homeCache: any
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (_, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
const result: any = getQueue()
|
const deemix = req.app.get('deemix')
|
||||||
|
const result: any = deemix.getQueue()
|
||||||
res.send(result)
|
res.send(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { getSettings } from '../../../main'
|
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getSettings'
|
const path: ApiHandler['path'] = '/getSettings'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (_, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
res.send(getSettings())
|
const deemix = req.app.get('deemix')
|
||||||
|
res.send(deemix.getSettings())
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiHandler: ApiHandler = { path, handler }
|
const apiHandler: ApiHandler = { path, handler }
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ, plugins } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getTracklist'
|
const path: ApiHandler['path'] = '/getTracklist'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = async (req, res) => {
|
const handler: ApiHandler['handler'] = async (req, res) => {
|
||||||
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
||||||
const dz = sessionDZ[req.session.id]
|
const dz = sessionDZ[req.session.id]
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
|
|
||||||
const list_id = String(req.query.id)
|
const list_id = String(req.query.id)
|
||||||
const list_type = String(req.query.type)
|
const list_type = String(req.query.type)
|
||||||
@ -20,7 +21,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
|
|||||||
}
|
}
|
||||||
case 'spotifyplaylist':
|
case 'spotifyplaylist':
|
||||||
case 'spotify_playlist': {
|
case 'spotify_playlist': {
|
||||||
if (!plugins.spotify.enabled) {
|
if (!deemix.plugins.spotify.enabled) {
|
||||||
res.send({
|
res.send({
|
||||||
collaborative: false,
|
collaborative: false,
|
||||||
description: '',
|
description: '',
|
||||||
@ -40,7 +41,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
|
|||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
const sp = plugins.spotify.sp
|
const sp = deemix.plugins.spotify.sp
|
||||||
let playlist = await sp.getPlaylist(list_id)
|
let playlist = await sp.getPlaylist(list_id)
|
||||||
playlist = playlist.body
|
playlist = playlist.body
|
||||||
let tracklist = playlist.tracks.items
|
let tracklist = playlist.tracks.items
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserAlbums'
|
const path: ApiHandler['path'] = '/getUserAlbums'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserArtists'
|
const path: ApiHandler['path'] = '/getUserArtists'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserFavorites'
|
const path: ApiHandler['path'] = '/getUserFavorites'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserPlaylists'
|
const path: ApiHandler['path'] = '/getUserPlaylists'
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { plugins } from '../../../main'
|
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserSpotifyPlaylists'
|
const path: ApiHandler['path'] = '/getUserSpotifyPlaylists'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = async (req, res) => {
|
const handler: ApiHandler['handler'] = async (req, res) => {
|
||||||
let data
|
let data
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
|
|
||||||
if (plugins.spotify.enabled) {
|
if (deemix.plugins.spotify.enabled) {
|
||||||
const sp = plugins.spotify.sp
|
const sp = deemix.plugins.spotify.sp
|
||||||
const username = req.query.spotifyUser
|
const username = req.query.spotifyUser
|
||||||
data = []
|
data = []
|
||||||
let playlists = await sp.getUserPlaylists(username)
|
let playlists = await sp.getUserPlaylists(username)
|
||||||
@ -22,7 +22,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
|
|||||||
playlistList = playlistList.concat(playlists.items)
|
playlistList = playlistList.concat(playlists.items)
|
||||||
}
|
}
|
||||||
playlistList.forEach((playlist: any) => {
|
playlistList.forEach((playlist: any) => {
|
||||||
data.push(plugins.spotify._convertPlaylistStructure(playlist))
|
data.push(deemix.plugins.spotify._convertPlaylistStructure(playlist))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
data = { error: 'spotifyNotEnabled' }
|
data = { error: 'spotifyNotEnabled' }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/getUserTracks'
|
const path: ApiHandler['path'] = '/getUserTracks'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/mainSearch'
|
const path: ApiHandler['path'] = '/mainSearch'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
import { getAlbumDetails } from './albumSearch'
|
import { getAlbumDetails } from './albumSearch'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/newReleases'
|
const path: ApiHandler['path'] = '/newReleases'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/search'
|
const path: ApiHandler['path'] = '/search'
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { plugins } from '../../../main'
|
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/spotifyStatus'
|
const path: ApiHandler['path'] = '/spotifyStatus'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (_, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
res.send({ spotifyEnabled: plugins.spotify.enabled })
|
const deemix = req.app.get('deemix')
|
||||||
|
res.send({ spotifyEnabled: deemix.plugins.spotify.enabled })
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiHandler: ApiHandler = { path, handler }
|
const apiHandler: ApiHandler = { path, handler }
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ, addToQueue, getSettings, listener } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/addToQueue'
|
const path: ApiHandler['path'] = '/addToQueue'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = async (req, res) => {
|
const handler: ApiHandler['handler'] = async (req, res) => {
|
||||||
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
const dz = sessionDZ[req.session.id]
|
const dz = sessionDZ[req.session.id]
|
||||||
|
|
||||||
const url = req.body.url.split(/[\s;]+/)
|
const url = req.body.url.split(/[\s;]+/)
|
||||||
let bitrate = req.body.bitrate
|
let bitrate = req.body.bitrate
|
||||||
if (bitrate === 'null' || bitrate === null) bitrate = getSettings().settings.maxBitrate
|
if (bitrate === 'null' || bitrate === null) bitrate = deemix.getSettings().settings.maxBitrate
|
||||||
let obj: any
|
let obj: any
|
||||||
|
|
||||||
try {
|
try {
|
||||||
obj = await addToQueue(dz, url, bitrate)
|
obj = await deemix.addToQueue(dz, url, bitrate)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
switch (e.name) {
|
switch (e.name) {
|
||||||
case 'NotLoggedIn':
|
case 'NotLoggedIn':
|
||||||
res.send({ result: false, errid: e.name, data: { url, bitrate } })
|
res.send({ result: false, errid: e.name, data: { url, bitrate } })
|
||||||
listener.send('loginNeededToDownload')
|
deemix.listener.send('loginNeededToDownload')
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { cancelAllDownloads } from '../../../main'
|
|
||||||
|
|
||||||
const path = '/cancelAllDownloads'
|
const path = '/cancelAllDownloads'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (_, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
cancelAllDownloads()
|
const deemix = req.app.get('deemix')
|
||||||
|
deemix.cancelAllDownloads()
|
||||||
res.send({ result: true })
|
res.send({ result: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { RequestHandler } from 'express'
|
|||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
|
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/changeAccount'
|
const path: ApiHandler['path'] = '/changeAccount'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RequestHandler } from 'express'
|
import { RequestHandler } from 'express'
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { sessionDZ, startQueue, isDeezerAvailable } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
|
|
||||||
export interface RawLoginArlBody {
|
export interface RawLoginArlBody {
|
||||||
@ -21,6 +21,7 @@ const path: ApiHandler['path'] = '/loginArl'
|
|||||||
|
|
||||||
const handler: RequestHandler<{}, {}, RawLoginArlBody, {}> = async (req, res, _) => {
|
const handler: RequestHandler<{}, {}, RawLoginArlBody, {}> = async (req, res, _) => {
|
||||||
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
const dz = sessionDZ[req.session.id]
|
const dz = sessionDZ[req.session.id]
|
||||||
|
|
||||||
if (!req.body) {
|
if (!req.body) {
|
||||||
@ -58,7 +59,7 @@ const handler: RequestHandler<{}, {}, RawLoginArlBody, {}> = async (req, res, _)
|
|||||||
response = await testDz.login_via_arl(...loginParams)
|
response = await testDz.login_via_arl(...loginParams)
|
||||||
}
|
}
|
||||||
if (response === LoginStatus.FAILED) sessionDZ[req.session.id] = new Deezer()
|
if (response === LoginStatus.FAILED) sessionDZ[req.session.id] = new Deezer()
|
||||||
if (!(await isDeezerAvailable())) response = LoginStatus.NOT_AVAILABLE
|
if (!(await deemix.isDeezerAvailable())) response = LoginStatus.NOT_AVAILABLE
|
||||||
const returnValue = {
|
const returnValue = {
|
||||||
status: response,
|
status: response,
|
||||||
arl: req.body.arl,
|
arl: req.body.arl,
|
||||||
@ -67,7 +68,7 @@ const handler: RequestHandler<{}, {}, RawLoginArlBody, {}> = async (req, res, _)
|
|||||||
currentChild: dz.selected_account
|
currentChild: dz.selected_account
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response !== LoginStatus.NOT_AVAILABLE && response !== LoginStatus.FAILED) startQueue(dz)
|
if (response !== LoginStatus.NOT_AVAILABLE && response !== LoginStatus.FAILED) deemix.startQueue(dz)
|
||||||
return res.status(200).send(returnValue)
|
return res.status(200).send(returnValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { getAccessToken, getArlFromAccessToken } from '../../../main'
|
import { getAccessToken, getArlFromAccessToken } from '../../../app'
|
||||||
|
|
||||||
const path = '/loginEmail'
|
const path = '/loginEmail'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { sessionDZ } from '../../../main'
|
import { sessionDZ } from '../../../app'
|
||||||
|
|
||||||
const path: ApiHandler['path'] = '/logout'
|
const path: ApiHandler['path'] = '/logout'
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { clearCompletedDownloads } from '../../../main'
|
|
||||||
|
|
||||||
const path = '/removeFinishedDownloads'
|
const path = '/removeFinishedDownloads'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (_, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
clearCompletedDownloads()
|
const deemix = req.app.get('deemix')
|
||||||
|
deemix.clearCompletedDownloads()
|
||||||
res.send({ result: true })
|
res.send({ result: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { ApiHandler } from '../../../types'
|
import { ApiHandler } from '../../../types'
|
||||||
import { cancelDownload } from '../../../main'
|
|
||||||
|
|
||||||
const path = '/removeFromQueue'
|
const path = '/removeFromQueue'
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (req, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
const { uuid } = req.query
|
const { uuid } = req.query
|
||||||
if (uuid) {
|
if (uuid) {
|
||||||
cancelDownload(uuid)
|
deemix.cancelDownload(uuid)
|
||||||
res.send({ result: true })
|
res.send({ result: true })
|
||||||
} else {
|
} else {
|
||||||
res.send({ result: false })
|
res.send({ result: false })
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ApiHandler, Settings, SpotifySettings } from '../../../types'
|
import { ApiHandler, Settings, SpotifySettings } from '../../../types'
|
||||||
import { saveSettings, listener } from '../../../main'
|
|
||||||
|
|
||||||
const path = '/saveSettings'
|
const path = '/saveSettings'
|
||||||
|
|
||||||
@ -9,9 +8,10 @@ export interface SaveSettingsData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handler: ApiHandler['handler'] = (req, res) => {
|
const handler: ApiHandler['handler'] = (req, res) => {
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
const { settings, spotifySettings }: SaveSettingsData = req.query
|
const { settings, spotifySettings }: SaveSettingsData = req.query
|
||||||
saveSettings(settings, spotifySettings)
|
deemix.saveSettings(settings, spotifySettings)
|
||||||
listener.send('updateSettings', { settings, spotifySettings })
|
deemix.listener.send('updateSettings', { settings, spotifySettings })
|
||||||
res.send({ result: true })
|
res.send({ result: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import express from 'express'
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { Deezer } from 'deezer-js'
|
import { Deezer } from 'deezer-js'
|
||||||
import { consoleInfo } from '../helpers/errors'
|
import { consoleInfo } from '../helpers/errors'
|
||||||
import { sessionDZ, getQueue, deemixVersion, currentVersion, isDeezerAvailable, plugins, getSettings } from '../main'
|
import { sessionDZ, deemixVersion, currentVersion } from '../app'
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
let update: any = null
|
let update: any = null
|
||||||
@ -10,6 +10,7 @@ let update: any = null
|
|||||||
router.get('/connect', async (req, res) => {
|
router.get('/connect', async (req, res) => {
|
||||||
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
if (!sessionDZ[req.session.id]) sessionDZ[req.session.id] = new Deezer()
|
||||||
const dz = sessionDZ[req.session.id]
|
const dz = sessionDZ[req.session.id]
|
||||||
|
const deemix = req.app.get('deemix')
|
||||||
|
|
||||||
if (!update) {
|
if (!update) {
|
||||||
consoleInfo(`Currently running deemix-gui version ${currentVersion}`)
|
consoleInfo(`Currently running deemix-gui version ${currentVersion}`)
|
||||||
@ -24,14 +25,14 @@ router.get('/connect', async (req, res) => {
|
|||||||
update,
|
update,
|
||||||
autologin: !dz.logged_in,
|
autologin: !dz.logged_in,
|
||||||
currentUser: dz.current_user,
|
currentUser: dz.current_user,
|
||||||
deezerAvailable: await isDeezerAvailable(),
|
deezerAvailable: await deemix.isDeezerAvailable(),
|
||||||
spotifyEnabled: plugins.spotify.enabled,
|
spotifyEnabled: deemix.plugins.spotify.enabled,
|
||||||
settingsData: getSettings()
|
settingsData: deemix.getSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.settingsData.settings.autoCheckForUpdates) result.checkForUpdates = true
|
if (result.settingsData.settings.autoCheckForUpdates) result.checkForUpdates = true
|
||||||
|
|
||||||
const queue = getQueue()
|
const queue = deemix.getQueue()
|
||||||
|
|
||||||
if (Object.keys(queue.queue).length > 0) {
|
if (Object.keys(queue.queue).length > 0) {
|
||||||
result.queue = queue
|
result.queue = queue
|
||||||
|
88
server/src/server.ts
Normal file
88
server/src/server.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import http, { Server } from 'http'
|
||||||
|
import express, { Application } from 'express'
|
||||||
|
import { Server as WsServer } from 'ws'
|
||||||
|
import initDebug from 'debug'
|
||||||
|
// @ts-expect-error
|
||||||
|
import deemix from 'deemix'
|
||||||
|
import { registerMiddlewares } from './middlewares'
|
||||||
|
import indexRouter from './routes'
|
||||||
|
import { getErrorCb, getListeningCb } from './helpers/server-callbacks'
|
||||||
|
import { registerApis } from './routes/api/register'
|
||||||
|
import { registerWebsocket } from './websocket'
|
||||||
|
import { consoleInfo } from './helpers/errors'
|
||||||
|
import { Port, Listener } from './types'
|
||||||
|
import { DeemixApp } from './app'
|
||||||
|
import { normalizePort } from './helpers/port'
|
||||||
|
|
||||||
|
export class DeemixServer {
|
||||||
|
host: string
|
||||||
|
port: Port
|
||||||
|
|
||||||
|
wss: WsServer
|
||||||
|
app: Application
|
||||||
|
server: Server
|
||||||
|
deemixApp: DeemixApp
|
||||||
|
|
||||||
|
constructor(host: string, port: string) {
|
||||||
|
this.host = host
|
||||||
|
this.port = normalizePort(port)
|
||||||
|
|
||||||
|
this.wss = new WsServer({ noServer: true })
|
||||||
|
this.app = express()
|
||||||
|
this.server = http.createServer(this.app)
|
||||||
|
|
||||||
|
const listener: Listener = {
|
||||||
|
send: (key: string, data?: any) => {
|
||||||
|
const logLine = deemix.utils.formatListener(key, data)
|
||||||
|
if (logLine) console.log(logLine)
|
||||||
|
if (['downloadInfo', 'downloadWarn'].includes(key)) return
|
||||||
|
this.wss.clients.forEach(client => {
|
||||||
|
if (client.readyState === WebSocket.OPEN) {
|
||||||
|
client.send(JSON.stringify({ key, data }))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deemixApp = new DeemixApp(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const debug = initDebug('deemix-gui:server')
|
||||||
|
this.app.set('deemix', this.deemixApp)
|
||||||
|
|
||||||
|
/* === Middlewares === */
|
||||||
|
registerMiddlewares(this.app)
|
||||||
|
|
||||||
|
/* === Routes === */
|
||||||
|
this.app.use('/', indexRouter)
|
||||||
|
|
||||||
|
/* === APIs === */
|
||||||
|
registerApis(this.app)
|
||||||
|
|
||||||
|
/* === Config === */
|
||||||
|
this.app.set('port', this.port)
|
||||||
|
|
||||||
|
/* === Server port === */
|
||||||
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
|
this.server.listen({ port: this.port, host: this.host })
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWebsocket(this.wss, this.deemixApp)
|
||||||
|
|
||||||
|
/* === Server callbacks === */
|
||||||
|
this.app.on('mount', a => {
|
||||||
|
console.log(a)
|
||||||
|
})
|
||||||
|
this.server.on('connect', () => {
|
||||||
|
consoleInfo('Server connected')
|
||||||
|
})
|
||||||
|
this.server.on('upgrade', (request, socket, head) => {
|
||||||
|
this.wss.handleUpgrade(request, socket, head, socket => {
|
||||||
|
this.wss.emit('connection', socket, request)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.server.on('error', getErrorCb(this.port))
|
||||||
|
this.server.on('listening', getListeningCb(this.server, debug))
|
||||||
|
}
|
||||||
|
}
|
@ -239,3 +239,7 @@ export interface Arguments {
|
|||||||
[x: string]: unknown
|
[x: string]: unknown
|
||||||
$0: string
|
$0: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Listener {
|
||||||
|
send: (key: string, data?: any) => void
|
||||||
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import { Server as WsServer } from 'ws'
|
import { Server as WsServer } from 'ws'
|
||||||
|
|
||||||
import { consoleError, consoleInfo } from '../helpers/errors'
|
import { consoleError, consoleInfo } from '../helpers/errors'
|
||||||
|
import { DeemixApp } from '../app'
|
||||||
import wsModules from './modules'
|
import wsModules from './modules'
|
||||||
|
|
||||||
// ? Is this needed?
|
export const registerWebsocket = (wss: WsServer, deemix: DeemixApp) => {
|
||||||
// ? https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
|
|
||||||
|
|
||||||
export const registerWebsocket = (wss: WsServer) => {
|
|
||||||
wss.on('connection', ws => {
|
wss.on('connection', ws => {
|
||||||
ws.on('message', message => {
|
ws.on('message', message => {
|
||||||
const data = JSON.parse(message.toString())
|
const data = JSON.parse(message.toString())
|
||||||
|
|
||||||
wsModules.forEach(module => {
|
wsModules.forEach(module => {
|
||||||
if (data.key === module.eventName) {
|
if (data.key === module.eventName) {
|
||||||
module.cb(data.data, ws, wss)
|
module.cb(data.data, ws, wss, deemix)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Server as WsServer } from 'ws'
|
import { Server as WsServer } from 'ws'
|
||||||
import { consoleInfo } from '../../helpers/errors'
|
import { consoleInfo } from '../../helpers/errors'
|
||||||
import { cancelAllDownloads } from '../../main'
|
import { DeemixApp } from '../../app'
|
||||||
|
|
||||||
const eventName = 'cancelAllDownloads'
|
const eventName = 'cancelAllDownloads'
|
||||||
|
|
||||||
const cb = (_: any, __: any, ___: WsServer) => {
|
const cb = (_: any, __: any, ___: WsServer, deemix: DeemixApp) => {
|
||||||
cancelAllDownloads()
|
deemix.cancelAllDownloads()
|
||||||
consoleInfo(`Queue cleared`)
|
consoleInfo(`Queue cleared`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Server as WsServer } from 'ws'
|
import { Server as WsServer } from 'ws'
|
||||||
import { consoleInfo } from '../../helpers/errors'
|
import { consoleInfo } from '../../helpers/errors'
|
||||||
import { clearCompletedDownloads } from '../../main'
|
import { DeemixApp } from '../../app'
|
||||||
|
|
||||||
const eventName = 'removeFinishedDownloads'
|
const eventName = 'removeFinishedDownloads'
|
||||||
|
|
||||||
const cb = (_: any, __: any, ___: WsServer) => {
|
const cb = (_: any, __: any, ___: WsServer, deemix: DeemixApp) => {
|
||||||
clearCompletedDownloads()
|
deemix.clearCompletedDownloads()
|
||||||
consoleInfo('Completed downloads cleared')
|
consoleInfo('Completed downloads cleared')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Server as WsServer } from 'ws'
|
import { Server as WsServer } from 'ws'
|
||||||
import { consoleInfo } from '../../helpers/errors'
|
import { consoleInfo } from '../../helpers/errors'
|
||||||
import { cancelDownload } from '../../main'
|
import { DeemixApp } from '../../app'
|
||||||
|
|
||||||
const eventName = 'removeFromQueue'
|
const eventName = 'removeFromQueue'
|
||||||
|
|
||||||
const cb = (data: any, __: any, ___: WsServer) => {
|
const cb = (data: any, __: any, ___: WsServer, deemix: DeemixApp) => {
|
||||||
cancelDownload(data)
|
deemix.cancelDownload(data)
|
||||||
consoleInfo(`Cancelled ${data}`)
|
consoleInfo(`Cancelled ${data}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Server as WsServer } from 'ws'
|
import { Server as WsServer } from 'ws'
|
||||||
import { consoleInfo } from '../../helpers/errors'
|
import { consoleInfo } from '../../helpers/errors'
|
||||||
import { saveSettings, listener } from '../../main'
|
import { DeemixApp } from '../../app'
|
||||||
import { Settings, SpotifySettings } from '../../types'
|
import { Settings, SpotifySettings } from '../../types'
|
||||||
|
|
||||||
const eventName = 'saveSettings'
|
const eventName = 'saveSettings'
|
||||||
@ -10,11 +10,11 @@ export interface SaveSettingsData {
|
|||||||
spotifySettings: SpotifySettings
|
spotifySettings: SpotifySettings
|
||||||
}
|
}
|
||||||
|
|
||||||
const cb = (data: SaveSettingsData, _: any, __: WsServer) => {
|
const cb = (data: SaveSettingsData, _: any, __: WsServer, deemix: DeemixApp) => {
|
||||||
const { settings, spotifySettings } = data
|
const { settings, spotifySettings } = data
|
||||||
saveSettings(settings, spotifySettings)
|
deemix.saveSettings(settings, spotifySettings)
|
||||||
consoleInfo('Settings saved')
|
consoleInfo('Settings saved')
|
||||||
listener.send('updateSettings', { settings, spotifySettings })
|
deemix.listener.send('updateSettings', { settings, spotifySettings })
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { eventName, cb }
|
export default { eventName, cb }
|
||||||
|
@ -6,7 +6,7 @@ module.exports = env => {
|
|||||||
const isProduction = !!env.production
|
const isProduction = !!env.production
|
||||||
const config = {
|
const config = {
|
||||||
mode: isProduction ? 'production' : 'development',
|
mode: isProduction ? 'production' : 'development',
|
||||||
entry: './src/app.ts',
|
entry: './src/index.ts',
|
||||||
devtool: isProduction ? false : 'eval',
|
devtool: isProduction ? false : 'eval',
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
2
webui
2
webui
@ -1 +1 @@
|
|||||||
Subproject commit 5fb5ae4ace6f271bee3cd744208197549738897d
|
Subproject commit c4cd5cb3b8cb49676d9e19761324a037cee3eab5
|
Loading…
Reference in New Issue
Block a user