From 5bf53028ef47e7f686c975d485234b658e8712c7 Mon Sep 17 00:00:00 2001 From: pan93412 Date: Wed, 26 Jan 2022 14:14:24 +0800 Subject: [PATCH] feat(server): allow passing modules manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自行維護 require 名單以相容 Webpack。 --- app.js | 2 +- server.js | 76 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/app.js b/app.js index 3e5e976..de14190 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,4 @@ #!/usr/bin/env node -require('./server')({ +require('./server').serveNcmApi({ checkVersion: true, }) diff --git a/server.js b/server.js index 483b04c..60585f1 100644 --- a/server.js +++ b/server.js @@ -20,11 +20,19 @@ const VERSION_CHECK_RESULT = { LATEST: 1, } +/** + * @typedef {{ + * route: string, + * module: any + * }} ModuleDefinition + */ + /** * @typedef {{ * port?: number, * host?: string, * checkVersion?: boolean, + * moduleDefs?: ModuleDefinition[] * }} NcmApiOptions */ @@ -42,6 +50,35 @@ const VERSION_CHECK_RESULT = { * }} ExpressExtension */ +/** + * Get the module definitions dynamically. + * + * @param {string} modulePath The path to modules (JS). + * @param {Record} [specificRoute] The specific route of specific modules. + * @returns {Promise} The module definitions. + * + * @example getModuleDefinitions("./module", {"album_new.js": "/album/create"}) + */ +async function getModulesDefinitions(modulePath, specificRoute) { + const files = await fs.promises.readdir(path.join(__dirname, 'module')) + const parseRoute = (/** @type {string} */ fileName) => + specificRoute && fileName in specificRoute + ? specificRoute[fileName] + : `/${fileName.replace(/\.js$/i, '').replace(/_/g, '/')}` + + const modules = files + .reverse() + .filter((file) => file.endsWith('.js')) + .map((file) => { + const route = parseRoute(file) + const module = require(path.join(modulePath, file)) + + return { route, module } + }) + + return modules +} + /** * Check if the version of this API is latest. * @@ -50,8 +87,8 @@ const VERSION_CHECK_RESULT = { * need to notify users to upgrade it manually. */ async function checkVersion() { - return new Promise((resolve, reject) => { - exec('npm info NeteaseCloudMusicApi version', (err, stdout, stderr) => { + return new Promise((resolve) => { + exec('npm info NeteaseCloudMusicApi version', (err, stdout) => { if (!err) { let version = stdout.trim() @@ -82,9 +119,10 @@ async function checkVersion() { /** * Construct the server of NCM API. * + * @param {ModuleDefinition[]} moduleDefs Customized module definitions [advanced] * @returns {Promise} The server instance. */ -async function consturctServer() { +async function consturctServer(moduleDefs) { const app = express() app.set('trust proxy', true) @@ -107,7 +145,7 @@ async function consturctServer() { /** * Cookie Parser */ - app.use((req, res, next) => { + app.use((req, _, next) => { req.cookies = {} //;(req.headers.cookie || '').split(/\s*;\s*/).forEach((pair) => { // Polynomial regular expression // ;(req.headers.cookie || '').split(/;\s+|(? { @@ -150,24 +188,13 @@ async function consturctServer() { /** * Load every modules in this directory */ - const modules = ( - await fs.promises.readdir(path.join(__dirname, 'module')) - ).reverse() - for (const file of modules) { - // Check if the file is written in JS. - if (!file.endsWith('.js')) continue - - // Get the route path. - const route = - file in special - ? special[file] - : '/' + file.replace(/\.js$/i, '').replace(/_/g, '/') - - // Get the module itself. - const module = require(path.join(__dirname, 'module', file)) + const moduleDefinitions = + moduleDefs || + (await getModulesDefinitions(path.join(__dirname, 'module'), special)) + for (const moduleDef of moduleDefinitions) { // Register the route. - app.use(route, async (req, res) => { + app.use(moduleDef.route, async (req, res) => { ;[req.query, req.body].forEach((item) => { if (typeof item.cookie === 'string') { item.cookie = cookieToJson(decode(item.cookie)) @@ -182,7 +209,7 @@ async function consturctServer() { ) try { - const moduleResponse = await module(query, request) + const moduleResponse = await moduleDef.module(query, request) console.log('[OK]', decode(req.originalUrl)) const cookies = moduleResponse.cookie @@ -242,7 +269,7 @@ async function serveNcmApi(options) { ) } }) - const constructServerSubmission = consturctServer() + const constructServerSubmission = consturctServer(options.moduleDefs) const [_, app] = await Promise.all([ checkVersionSubmission, @@ -258,4 +285,7 @@ async function serveNcmApi(options) { return appExt } -module.exports = serveNcmApi +module.exports = { + serveNcmApi, + getModulesDefinitions, +}