完成网络音乐、工具页面与安装器体验升级
This commit is contained in:
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @fileoverview KuGouMusicApi 程序化 API 入口模块
|
||||
*
|
||||
* 本模块是项目的编程式调用入口(区别于 index.js 的 HTTP 服务入口),
|
||||
* 负责:
|
||||
* 1. 扫描 `module/` 目录下所有 API 模块文件并动态加载
|
||||
* 2. 为每个模块创建统一的包装函数,自动处理 Cookie 格式转换
|
||||
* 3. 将所有 API 函数与服务器工具、请求工具合并后统一导出
|
||||
*
|
||||
* 导出结构为扁平对象,模块文件名(去 .js 后缀)即为 API 函数名。
|
||||
* 例如:`module/search.js` → `api.search(params)`
|
||||
*
|
||||
* @module app
|
||||
* @requires node:fs
|
||||
* @requires path
|
||||
* @requires ./util - 工具函数(cookieToJson 等)
|
||||
* @requires ./server - 服务器管理(startService、getModulesDefinitions)
|
||||
* @requires ./util/request - 底层 HTTP 请求工具(createRequest)
|
||||
*
|
||||
* @example
|
||||
* // 作为库使用(编程式调用,不启动 HTTP 服务)
|
||||
* const api = require('./app');
|
||||
*
|
||||
* // 手机登录
|
||||
* const loginRes = await api.login_cellphone({
|
||||
* mobile: '13800138000',
|
||||
* code: '123456'
|
||||
* });
|
||||
*
|
||||
* // 搜索音乐(携带认证 Cookie)
|
||||
* const searchRes = await api.search({
|
||||
* keywords: '海阔天空',
|
||||
* cookie: `token=${loginRes.body.token};userid=${loginRes.body.userid}`
|
||||
* });
|
||||
*/
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('path');
|
||||
const { cookieToJson } = require('./util');
|
||||
|
||||
/**
|
||||
* 动态注册的 API 函数集合
|
||||
*
|
||||
* 键为模块文件名(去 .js 后缀),值为对应的包装函数。
|
||||
* 例如:`{ search: [Function], login_cellphone: [Function], ... }`
|
||||
*
|
||||
* @type {Record<string, (data?: Record<string, any>) => Promise<any>>}
|
||||
*/
|
||||
let obj = {};
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 动态扫描并加载 module/ 目录下的所有 API 模块
|
||||
* ============================================================
|
||||
*
|
||||
* 扫描流程:
|
||||
* 1. 使用 `fs.readdirSync` 同步读取 `module/` 目录下所有文件
|
||||
* 2. 对文件列表进行倒序排列(与 server.js 中的路由注册顺序保持一致)
|
||||
* 3. 过滤出以 `.js` 结尾的文件
|
||||
* 4. 对每个模块文件:
|
||||
* a. 通过 `require` 加载模块,获取模块处理函数
|
||||
* b. 从文件名提取 API 函数名(去掉 `.js` 后缀,如 `search.js` → `search`)
|
||||
* c. 创建包装函数并注册到 `obj` 对象中
|
||||
*
|
||||
* 每个包装函数的作用:
|
||||
* - 将调用者传入的 cookie 字符串自动转换为 JSON 对象
|
||||
* - 合并调用参数与默认 cookie
|
||||
* - 调用原始模块处理函数,同时注入请求工厂函数(lazy 加载 createRequest)
|
||||
*/
|
||||
fs.readdirSync(path.join(__dirname, 'module'))
|
||||
.reverse()
|
||||
.forEach((file) => {
|
||||
// 跳过非 .js 文件(如 .json、.map、目录等)
|
||||
if (!file.endsWith('.js')) return;
|
||||
|
||||
// 加载模块,获取其导出的处理函数
|
||||
let fileModule = require(path.join(__dirname, 'module', file));
|
||||
|
||||
// 提取 API 函数名:取文件名中第一个 `.` 之前的部分
|
||||
// 例如:`search.js` → `search`,`login_cellphone.js` → `login_cellphone`
|
||||
let fn = file.split('.').shift() || '';
|
||||
|
||||
/**
|
||||
* 为当前模块创建包装函数
|
||||
*
|
||||
* @param {Record<string, any>} [data={}] - 调用者传入的请求参数
|
||||
* @returns {Promise<any>} 模块处理函数的返回结果
|
||||
*/
|
||||
obj[fn] = (data = {}) => {
|
||||
// 自动将 cookie 字符串转换为 JSON 对象
|
||||
// 调用者可以传入 cookie 字符串(如 "token=xxx;userid=xxx")或对象格式
|
||||
if (typeof data.cookie === 'string') data.cookie = cookieToJson(data.cookie);
|
||||
|
||||
// 调用原始模块处理函数,传入两个参数:
|
||||
// 1. 合并后的参数对象(确保 cookie 始终为对象格式,默认为空对象)
|
||||
// 2. 请求工厂函数:延迟加载 createRequest,避免循环依赖
|
||||
return fileModule({ ...data, cookie: data.cookie ? data.cookie : {} }, (...args) => {
|
||||
// 延迟加载:仅在实际需要发起请求时才 require createRequest
|
||||
// 这样可以避免模块加载阶段的循环依赖问题
|
||||
const { createRequest } = require('./util/request');
|
||||
return createRequest(...args);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 统一导出
|
||||
* ============================================================
|
||||
*
|
||||
* 最终导出一个扁平对象,包含三部分内容:
|
||||
*
|
||||
* 1. `...require('./server')` — 服务器管理工具
|
||||
* - `startService()`: 启动 HTTP 服务
|
||||
* - `getModulesDefinitions()`: 动态扫描模块定义
|
||||
*
|
||||
* 2. `...require('./util/request')` — 底层请求工具
|
||||
* - `createRequest()`: 创建 HTTP 请求
|
||||
*
|
||||
* 3. `...obj` — 所有 API 模块函数
|
||||
* - 每个 module/*.js 文件对应一个同名函数
|
||||
* - 如 `search`、`login_cellphone`、`song_url` 等
|
||||
*
|
||||
* @type {Record<string, any> & import("./server")}
|
||||
*/
|
||||
module.exports = { ...require('./server'), ...require('./util/request'), ...obj };
|
||||
Reference in New Issue
Block a user