1- import { computeHash , deepCopy } from "../utils/utils.js " ;
1+ import path from "path " ;
22import { readFile } from "fs/promises" ;
3+ import { getSitesMap } from "../utils/sites-map.js" ;
4+ import { computeHash , deepCopy , getNowTime } from "../utils/utils.js" ;
5+ import { fileURLToPath } from 'url' ;
36import { md5 } from "../libs_drpy/crypto-util.js" ;
7+ import { PythonShell , PythonShellError } from 'python-shell' ;
8+ import { fastify } from "../controllers/fastlogger.js" ;
49
10+ // 缓存已初始化的模块和文件 hash 值
511const moduleCache = new Map ( ) ;
6-
7-
8- const getRule = async function ( filePath , env ) {
9- const moduleObject = await init ( filePath , env ) ;
10- return JSON . stringify ( moduleObject ) ;
11- }
12+ const ruleObjectCache = new Map ( ) ;
13+ const __dirname = path . dirname ( fileURLToPath ( import . meta . url ) ) ;
14+ const _data_path = path . join ( __dirname , '../data' ) ;
15+ const _config_path = path . join ( __dirname , '../config' ) ;
16+ const _lib_path = path . join ( __dirname , '../spider/py' ) ;
17+ const timeout = 30000 ; // 30秒超时
1218
1319const json2Object = function ( json ) {
20+ // console.log('json2Object:', json);
1421 if ( ! json ) {
1522 return { }
1623 } else if ( json && typeof json === 'object' ) {
@@ -19,23 +26,147 @@ const json2Object = function (json) {
1926 return JSON . parse ( json ) ;
2027}
2128
29+ const loadEsmWithHash = async function ( filePath , fileHash , env ) {
30+ // 创建Python模块代理
31+ const spiderProxy = { } ;
32+ const bridgePath = path . join ( _lib_path , '_bridge.py' ) ; // 桥接脚本路径
33+
34+ // 创建方法调用函数
35+ const callPythonMethod = async ( methodName , ...args ) => {
36+
37+ const options = {
38+ mode : 'text' , // 使用JSON模式自动解析
39+ pythonOptions : [ '-u' ] , // 无缓冲输出
40+ // scriptPath: path.dirname(bridgePath),
41+ timeout : timeout ,
42+ env : {
43+ "PYTHONIOENCODING" : 'utf-8' ,
44+ }
45+ } ;
46+ // 将参数序列化为JSON字符串
47+ const jsonArgs = args . map ( arg => JSON . stringify ( arg ) ) ;
48+ console . log ( methodName , ...jsonArgs ) ;
49+ try {
50+ const results = await PythonShell . run ( bridgePath , {
51+ ...options ,
52+ args : [ filePath , methodName , ...jsonArgs ]
53+ } ) ;
54+ // 取最后一条返回
55+ let vodResult = results . slice ( - 1 ) [ 0 ] ;
56+ // if (methodName !== 'init') {
57+ // console.log(vodResult);
58+ // }
59+ if ( typeof vodResult === 'string' && vodResult ) {
60+ switch ( vodResult ) {
61+ case 'None' :
62+ vodResult = null ;
63+ break ;
64+ case 'True' :
65+ vodResult = true ;
66+ break ;
67+ case 'False' :
68+ vodResult = false ;
69+ break ;
70+ default :
71+ vodResult = JSON5 . parse ( vodResult ) ;
72+ break ;
73+
74+ }
75+ }
76+ // console.log('hipy logs:', results.slice(0, -1));
77+ fastify . log . info ( `hipy logs: ${ JSON . stringify ( results . slice ( 0 , - 1 ) ) } ` ) ;
78+ // fastify.log.info(`typeof vodResult: ${typeof vodResult}`);
79+ // console.log('vodResult:', vodResult);
80+ // 检查是否有错误
81+ if ( vodResult && vodResult . error ) {
82+ throw new Error ( `Python错误: ${ vodResult . error } \n${ vodResult . traceback } ` ) ;
83+ }
84+
85+ return vodResult ; // 返回最后1个结果集
86+ } catch ( error ) {
87+ console . error ( 'error:' , error ) ;
88+ if ( error instanceof PythonShellError ) {
89+ // 尝试解析Python的错误输出
90+ try {
91+ const errorData = JSON . parse ( error . message ) ;
92+ throw new Error ( `Python错误: ${ errorData . error } \n${ errorData . traceback } ` ) ;
93+ } catch ( e ) {
94+ throw new Error ( `Python执行错误: ${ error . message } ` ) ;
95+ }
96+ }
97+ throw error ;
98+ }
99+ } ;
100+
101+ // 定义Spider类的方法
102+ const spiderMethods = [
103+ 'init' , 'home' , 'homeVod' , 'homeContent' , 'category' ,
104+ 'detail' , 'search' , 'play' , 'proxy' , 'action' , 'initEnv'
105+ ] ;
106+
107+ // 为代理对象添加方法
108+ spiderMethods . forEach ( method => {
109+ spiderProxy [ method ] = async ( ...args ) => {
110+ return callPythonMethod ( method , ...args ) ;
111+ } ;
112+ } ) ;
113+
114+ // 处理initEnv调用
115+ if ( typeof spiderProxy . initEnv === 'function' && env ) {
116+ await spiderProxy . initEnv ( env ) ;
117+ }
118+
119+ return spiderProxy ;
120+ }
121+
122+ const getRule = async function ( filePath , env ) {
123+ const moduleObject = await init ( filePath , env ) ;
124+ return JSON . stringify ( moduleObject ) ;
125+ }
126+
22127const init = async function ( filePath , env = { } , refresh ) {
23128 try {
129+ // console.log('execute init');
24130 const fileContent = await readFile ( filePath , 'utf-8' ) ;
25131 const fileHash = computeHash ( fileContent ) ;
132+ const moduleName = path . basename ( filePath , '.js' ) ;
26133 let moduleExt = env . ext || '' ;
134+ const default_init_cfg = {
135+ stype : 4 , //T3/T4 源类型
136+ skey : `hipy_${ moduleName } ` ,
137+ sourceKey : `hipy_${ moduleName } ` ,
138+ ext : moduleExt ,
139+ } ;
140+ let SitesMap = getSitesMap ( _config_path ) ;
141+ if ( moduleExt && SitesMap [ moduleName ] ) {
142+ try {
143+ moduleExt = ungzip ( moduleExt ) ;
144+ } catch ( e ) {
145+ log ( `[${ moduleName } ] ungzip解密moduleExt失败: ${ e . message } ` ) ;
146+ }
147+ if ( ! SitesMap [ moduleName ] . find ( i => i . queryStr === moduleExt ) && ! SitesMap [ moduleName ] . find ( i => i . queryObject . params === moduleExt ) ) {
148+ throw new Error ( "moduleExt is wrong!" )
149+ }
150+ }
27151 let hashMd5 = md5 ( filePath + '#pAq#' + moduleExt ) ;
28152 if ( moduleCache . has ( hashMd5 ) && ! refresh ) {
29153 const cached = moduleCache . get ( hashMd5 ) ;
30- if ( cached . hash === fileHash ) {
154+ // 除hash外还必须保证proxyUrl实时相等,避免本地代理url的尴尬情况
155+ if ( cached . hash === fileHash && cached . proxyUrl === env . proxyUrl ) {
31156 return cached . moduleObject ;
32157 }
33158 }
34159 log ( `Loading module: ${ filePath } ` ) ;
35- let rule = { } ;
36- await rule . init ( moduleExt || { } ) ;
160+ let t1 = getNowTime ( ) ;
161+ let module ;
162+ module = await loadEsmWithHash ( filePath , fileHash , env ) ;
163+ // console.log('module:', module);
164+ const rule = module ;
165+ await rule . init ( default_init_cfg ) ;
166+ let t2 = getNowTime ( ) ;
37167 const moduleObject = deepCopy ( rule ) ;
38- moduleCache . set ( hashMd5 , { moduleObject, hash : fileHash } ) ;
168+ moduleObject . cost = t2 - t1 ;
169+ moduleCache . set ( hashMd5 , { moduleObject, hash : fileHash , proxyUrl : env . proxyUrl } ) ;
39170 return moduleObject ;
40171 } catch ( error ) {
41172 console . log ( `Error in hipy.init :${ filePath } ` , error ) ;
@@ -50,11 +181,12 @@ const home = async function (filePath, env, filter = 1) {
50181
51182const homeVod = async function ( filePath , env ) {
52183 const moduleObject = await init ( filePath , env ) ;
53- return json2Object ( await moduleObject . homeVod ( ) ) ;
184+ const homeVodResult = json2Object ( await moduleObject . homeVod ( ) ) ;
185+ return homeVodResult && homeVodResult . list ? homeVodResult . list : homeVodResult ;
54186}
55187
56188
57- const cate = async function ( filePath , env , tid , pg = 1 , filter = 1 , extend = { } ) {
189+ const category = async function ( filePath , env , tid , pg = 1 , filter = 1 , extend = { } ) {
58190 const moduleObject = await init ( filePath , env ) ;
59191 return json2Object ( await moduleObject . category ( tid , pg , filter , extend ) ) ;
60192}
@@ -91,7 +223,7 @@ export default {
91223 init,
92224 home,
93225 homeVod,
94- cate ,
226+ category ,
95227 detail,
96228 search,
97229 play,
0 commit comments