/** * XBPQ (小白盘棋) 模块 * * 提供视频源规则的加载、缓存和执行功能 * 支持首页、分类、详情、搜索、播放等核心功能 * * 主要功能: * - 规则文件的动态加载和缓存 * - 视频源的各种操作接口 * - 模块生命周期管理 * * @author drpy-node * @version 1.0.0 */ import {computeHash, deepCopy} from "../utils/utils.js"; import {readFile} from "fs/promises"; import {md5} from "../libs_drpy/crypto-util.js"; // 模块缓存,用于存储已加载的模块以提高性能 const moduleCache = new Map(); /** * 获取规则的JSON字符串表示 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量和配置 * @returns {Promise} 规则对象的JSON字符串 */ const getRule = async function (filePath, env) { const moduleObject = await init(filePath, env); return JSON.stringify(moduleObject); } /** * 将JSON字符串或对象转换为JavaScript对象 * * @param {string|Object} json - JSON字符串或对象 * @returns {Object} 转换后的JavaScript对象 */ const json2Object = function (json) { if (!json) { return {} } else if (json && typeof json === 'object') { return json } return JSON.parse(json); } /** * 初始化模块 * * 加载指定路径的规则文件,支持缓存机制以提高性能 * 如果文件内容未变化且缓存存在,则直接返回缓存的模块对象 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量,包含ext等配置 * @param {boolean} refresh - 是否强制刷新缓存 * @returns {Promise} 初始化后的模块对象 * @throws {Error} 当模块初始化失败时抛出错误 */ const init = async function (filePath, env = {}, refresh) { try { // 读取文件内容并计算哈希值用于缓存验证 const fileContent = await readFile(filePath, 'utf-8'); const fileHash = computeHash(fileContent); let moduleExt = env.ext || ''; let hashMd5 = md5(filePath + '#pAq#' + moduleExt); // 检查缓存是否存在且有效 if (moduleCache.has(hashMd5) && !refresh) { const cached = moduleCache.get(hashMd5); if (cached.hash === fileHash) { return cached.moduleObject; } } log(`Loading module: ${filePath}`); let rule = {}; // 初始化规则模块 await rule.init(moduleExt || {}); const moduleObject = deepCopy(rule); // 将模块对象存入缓存 moduleCache.set(hashMd5, {moduleObject, hash: fileHash}); return moduleObject; } catch (error) { console.log(`Error in xbpq.init :${filePath}`, error); throw new Error(`Failed to initialize module:${error.message}`); } } /** * 获取首页数据 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {number} filter - 过滤器参数,默认为1 * @returns {Promise} 首页数据对象 */ const home = async function (filePath, env, filter = 1) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.home(filter)); } /** * 获取首页推荐视频数据 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @returns {Promise} 首页推荐视频数据对象 */ const homeVod = async function (filePath, env) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.homeVod()); } /** * 获取分类页面数据 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {string} tid - 分类ID * @param {number} pg - 页码,默认为1 * @param {number} filter - 过滤器参数,默认为1 * @param {Object} extend - 扩展参数,默认为空对象 * @returns {Promise} 分类页面数据对象 */ const category = async function (filePath, env, tid, pg = 1, filter = 1, extend = {}) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.category(tid, pg, filter, extend)); } /** * 获取视频详情数据 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {string} ids - 视频ID列表 * @returns {Promise} 视频详情数据对象 */ const detail = async function (filePath, env, ids) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.detail(ids)); } /** * 执行搜索操作 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {string} wd - 搜索关键词 * @param {number} quick - 快速搜索标志,默认为0 * @param {number} pg - 页码,默认为1 * @returns {Promise} 搜索结果数据对象 */ const search = async function (filePath, env, wd, quick = 0, pg = 1) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.search(wd, quick, pg)); } /** * 获取播放地址 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {string} flag - 播放标志 * @param {string} id - 播放ID * @param {Array} flags - 播放标志列表 * @returns {Promise} 播放地址数据对象 */ const play = async function (filePath, env, flag, id, flags) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.play(flag, id, flags)); } /** * 代理请求处理 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {Object} params - 代理参数 * @returns {Promise} 代理响应数据对象 */ const proxy = async function (filePath, env, params) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.proxy(params)); } /** * 执行自定义动作 * * @param {string} filePath - 规则文件路径 * @param {Object} env - 环境变量 * @param {string} action - 动作名称 * @param {*} value - 动作参数值 * @returns {Promise} 动作执行结果数据对象 */ const action = async function (filePath, env, action, value) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.action(action, value)); } // 导出所有API方法 export default { getRule, // 获取规则 init, // 初始化模块 home, // 首页数据 homeVod, // 首页推荐 category, // 分类数据 detail, // 详情数据 search, // 搜索功能 play, // 播放地址 proxy, // 代理请求 action, // 自定义动作 }