import path from "path"; import {readFile} from "fs/promises"; import {getSitesMap} from "../utils/sites-map.js"; import {computeHash, deepCopy, getNowTime} from "../utils/utils.js"; import {fileURLToPath, pathToFileURL} from 'url'; import {md5} from "../libs_drpy/crypto-util.js"; // 缓存已初始化的模块和文件 hash 值 const moduleCache = new Map(); const ruleObjectCache = new Map(); const __dirname = path.dirname(fileURLToPath(import.meta.url)); const _data_path = path.join(__dirname, '../data'); const _config_path = path.join(__dirname, '../config'); const _lib_path = path.join(__dirname, '../spider/catvod'); const json2Object = function (json) { if (!json) { return {} } else if (json && typeof json === 'object') { return json } return JSON.parse(json); } const loadEsmWithHash = async function (filePath, fileHash) { const scriptUrl = `${pathToFileURL(filePath).href}?v=${fileHash}`; return await import(scriptUrl); } const loadEsmWithEnv = async function (filePath, env) { const rawCode = await readFile(filePath, 'utf8'); let injectedCode = rawCode; const esm_flag1 = 'export function __jsEvalReturn'; const esm_flag2 = 'export default'; const polyfill_code = 'var ENV={};\nvar getProxyUrl=null;\nexport const initEnv = (env)=>{ENV = env;if(env.getProxyUrl){getProxyUrl=env.getProxyUrl}};\n'; if (rawCode.includes(esm_flag1)) { injectedCode = rawCode.replace(esm_flag1, `${polyfill_code}${esm_flag1}`) } else if (rawCode.includes('export default')) { injectedCode = rawCode.replace(esm_flag2, `${polyfill_code}${esm_flag2}`) } // console.log(injectedCode); // // 创建数据URI模块 const dataUri = `data:text/javascript;base64,${Buffer.from(injectedCode).toString('base64')}`; const module = await import(dataUri); const initEnv = module.initEnv; if (typeof initEnv === 'function' && env) { initEnv(env); } return module } const getRule = async function (filePath, env) { const moduleObject = await init(filePath, env); return JSON.stringify(moduleObject); } const init = async function (filePath, env = {}, refresh) { try { const fileContent = await readFile(filePath, 'utf-8'); const fileHash = computeHash(fileContent); const moduleName = path.basename(filePath, '.js'); let moduleExt = env.ext || ''; let SitesMap = getSitesMap(_config_path); if (moduleExt && SitesMap[moduleName]) { try { moduleExt = ungzip(moduleExt); } catch (e) { log(`[${moduleName}] ungzip解密moduleExt失败: ${e.message}`); } if (!SitesMap[moduleName].find(i => i.queryStr === moduleExt) && !SitesMap[moduleName].find(i => i.queryObject.params === moduleExt)) { throw new Error("moduleExt is wrong!") } } let hashMd5 = md5(filePath + '#pAq#' + moduleExt); if (moduleCache.has(hashMd5) && !refresh) { const cached = moduleCache.get(hashMd5); // 除hash外还必须保证proxyUrl实时相等,避免本地代理url的尴尬情况 if (cached.hash === fileHash && cached.proxyUrl === env.proxyUrl) { return cached.moduleObject; } } log(`Loading module: ${filePath}`); let t1 = getNowTime(); const module = await loadEsmWithEnv(filePath, env); // console.log('module:', module); let rule; if (module && module.__jsEvalReturn && typeof module.__jsEvalReturn === 'function') { rule = module.__jsEvalReturn(); } else { rule = module.default || module; } // console.log('rule:', rule); // console.log('globalThis.ENV:', globalThis.ENV); // console.log('globalThis.getProxyUrl:', globalThis.getProxyUrl); // 加载 init await rule.init(moduleExt || {}); let t2 = getNowTime(); const moduleObject = deepCopy(rule); moduleObject.cost = t2 - t1; moduleCache.set(hashMd5, {moduleObject, hash: fileHash, proxyUrl: env.proxyUrl}); return moduleObject; } catch (error) { console.log(`Error in catvod.init :${filePath}`, error); throw new Error(`Failed to initialize module:${error.message}`); } } const home = async function (filePath, env, filter = 1) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.home(filter)); } const homeVod = async function (filePath, env) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.homeVod()); } const cate = 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)); } const detail = async function (filePath, env, ids) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.detail(ids)); } 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)); } const play = async function (filePath, env, flag, id, flags) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.play(flag, id, flags)); } const proxy = async function (filePath, env, params) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.proxy(params)); } const action = async function (filePath, env, action, value) { const moduleObject = await init(filePath, env); return json2Object(await moduleObject.action(action, value)); } export default { getRule, init, home, homeVod, cate, detail, search, play, proxy, action, }