Skip to content

Commit 49c6566

Browse files
committed
update:增加es6扩展。尝试写源支持方法的局部变量input等等,失败告终
1 parent 543faec commit 49c6566

File tree

8 files changed

+414
-39
lines changed

8 files changed

+414
-39
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ todo:
88

99
1. js里的源能否去除export开头,保持跟qjs一致
1010
2. js里的源,像一级这种异步js,里面调用未定义的函数,能否不通过函数参数传入直接注入调用
11+
3. 在源的各个函数调用的时候动态注入input、MY_URL等局部变量不影响全局。搞了半天没成功,有点难受,待解决

Diff for: index.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fastify.get('/api/:module', async (request, reply) => {
1515
const query = request.query; // 获取 query 参数
1616
const modulePath = path.join(__dirname, 'js', `${moduleName}.js`);
1717

18+
const pg = Number(query.pg) || 1;
1819
try {
1920
// 根据 query 参数决定执行逻辑
2021
if ('play' in query) {
@@ -33,7 +34,7 @@ fastify.get('/api/:module', async (request, reply) => {
3334
}
3435
}
3536
// 分类逻辑
36-
const result = await drpy.cate(modulePath, query.t, query.pg || 1, extend);
37+
const result = await drpy.cate(modulePath, query.t, pg, extend);
3738
return reply.send(result);
3839
}
3940

@@ -48,7 +49,7 @@ fastify.get('/api/:module', async (request, reply) => {
4849
if (!('quick' in query)) {
4950
query.quick = 0
5051
}
51-
const result = await drpy.search(modulePath, query.wd, query.quick, query.pg || 1);
52+
const result = await drpy.search(modulePath, query.wd, query.quick, pg);
5253
return reply.send(result);
5354
}
5455

@@ -64,7 +65,7 @@ fastify.get('/api/:module', async (request, reply) => {
6465
const result_home = await drpy.home(modulePath, query.filter);
6566
const result_homeVod = await drpy.homeVod(modulePath);
6667
const result = {
67-
class: result_home,
68+
...result_home,
6869
list: result_homeVod
6970
}
7071
reply.send(result);

Diff for: js/fq.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// http://localhost:5757/api/番茄小说[书]?ac=list&t=主分类&pg=1
2+
var rule = {
3+
类型: '小说',
4+
title: '番茄小说[书]',
5+
desc: '番茄小说纯js版本',
6+
host: 'https://fanqienovel.com/',
7+
homeUrl: 'https://fanqienovel.com/api/author/book/category_list/v0/',
8+
url: '/api/author/library/book_list/v0/?page_count=18&page_index=(fypage-1)&gender=-1&category_id=fyclass&creation_status=-1&word_count=-1&sort=0#fyfilter',
9+
class_parse: async () => {
10+
11+
},
12+
预处理: async () => {
13+
},
14+
推荐: async () => {
15+
return []
16+
},
17+
一级: async (tid, pg, filter, extend) => {
18+
console.log(input);
19+
console.log({tid,pg,filter,extend});
20+
console.log(rule.host);
21+
console.log(rule.host.rstrip('/'));
22+
},
23+
二级: async () => {
24+
return '这是二级:' + rule.title
25+
},
26+
搜索: async () => {
27+
return '这是搜索:' + rule.title
28+
},
29+
lazy: async () => {
30+
return template.getMubans()
31+
},
32+
};

Diff for: js/番茄小说[书].js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// http://localhost:5757/api/番茄小说[书]?ac=list&t=主分类&pg=1
2+
var rule = {
3+
类型: '小说',
4+
title: '番茄小说[书]',
5+
desc: '番茄小说纯js版本',
6+
host: 'https://fanqienovel.com/',
7+
homeUrl: 'https://fanqienovel.com/api/author/book/category_list/v0/',
8+
url: '/api/author/library/book_list/v0/?page_count=18&page_index=(fypage-1)&gender=-1&category_id=fyclass&creation_status=-1&word_count=-1&sort=0#fyfilter',
9+
searchUrl:'https://api5-normal-lf.fqnovel.com/reading/bookapi/search/page/v/?query=**&aid=1967&channel=0&os_version=0&device_type=0&device_platform=0&iid=466614321180296&passback=((fypage-1)*10)&version_code=999',
10+
searchable: 2,
11+
quickSearch: 0,
12+
filterable: 1,
13+
filter: '',
14+
filter_url: '{{fl.筛选}}',
15+
filter_def: {
16+
//全部: {筛选: '-1'},
17+
主分类: {筛选: '1016'},//男频衍生
18+
主题: {筛选: '516'},//都市异能
19+
角色: {筛选: '29'},//如懿衍生
20+
情节: {筛选: '1034'},//如懿衍生
21+
},
22+
headers: {
23+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
24+
},
25+
config: {
26+
api: 'https://novel.snssdk.com/api',
27+
封面域名: 'http://p6-novel.byteimg.com/large/',
28+
},
29+
timeout: 5000,
30+
play_parse: true,
31+
class_parse: async () => {
32+
let html = (await req(rule.homeUrl)).content;
33+
let json = JSON.parse(html);
34+
let data_list = json.data;
35+
let ret = {};
36+
for (let data of data_list) {
37+
if (!ret[data.label]) {
38+
ret[data.label] = {
39+
title: [],
40+
url: []
41+
}
42+
}
43+
ret[data.label].title.push(data.name);
44+
ret[data.label].url.push(data.category_id);
45+
}
46+
let classes = [];
47+
let filters = {};
48+
let keys = Object.keys(ret);
49+
for (let key of keys) {
50+
let _titles = ret[key].title;
51+
let _urls = ret[key].url;
52+
classes.push({
53+
type_name: key,
54+
type_id: key,
55+
});
56+
filters[key] = [{
57+
key: '筛选',
58+
name: '筛选',
59+
value: _titles.map((it, index) => {
60+
return {
61+
n: it,
62+
v: _urls[index]
63+
}
64+
})
65+
}];
66+
}
67+
classes.unshift({
68+
type_name: '全部',
69+
type_id: '-1',
70+
});
71+
return {class:classes,filters}
72+
},
73+
预处理: async () => {
74+
},
75+
推荐: async () => {
76+
return []
77+
},
78+
一级: async (tid, pg, filter, extend) => {
79+
console.log({tid,pg,filter,extend});
80+
console.log(`input:${input},MY_URL:${MY_URL}`);
81+
console.log(rule.host);
82+
console.log(rule.host.rstrip('/'));
83+
},
84+
二级: async () => {
85+
return '这是二级:' + rule.title
86+
},
87+
搜索: async () => {
88+
return '这是搜索:' + rule.title
89+
},
90+
lazy: async () => {
91+
return template.getMubans()
92+
},
93+
};

Diff for: libs/drpy.js

+105-32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {readFile} from 'fs/promises';
2-
import crypto from 'crypto';
2+
import {readFileSync} from 'fs';
3+
import path from "path";
34
import vm from 'vm';
5+
import '../libs_drpy/es6-extend.js'
46
import * as utils from '../utils/utils.js';
57
// const { req } = await import('../utils/req.js');
68
import {matchesAll, stringUtils, cut} from '../libs_drpy/external.js'
@@ -14,21 +16,16 @@ import '../libs_drpy/node-rsa.js';
1416
import '../libs_drpy/pako.min.js';
1517
import '../libs_drpy/json5.js'
1618
import '../libs_drpy/jinja.js'
19+
import {fileURLToPath} from "url";
1720

18-
const {sleep, sleepSync} = utils
19-
21+
const {sleep, sleepSync, computeHash} = utils
22+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
23+
const es6JsPath = path.join(__dirname, '../libs_drpy/es6-extend.js');
24+
// 读取扩展代码
25+
const es6_extend_code = readFileSync(es6JsPath, 'utf8');
2026
// 缓存已初始化的模块和文件 hash 值
2127
const moduleCache = new Map();
2228

23-
/**
24-
* 计算文件内容的 hash 值
25-
* @param {string} content - 文件内容
26-
* @returns {string} - 文件内容的 hash 值
27-
*/
28-
function computeHash(content) {
29-
return crypto.createHash('sha256').update(content, 'utf8').digest('hex');
30-
}
31-
3229
/**
3330
* 初始化模块:加载并执行模块文件,存储初始化后的 rule 对象
3431
* 如果存在 `预处理` 属性且为函数,会在缓存前执行
@@ -40,7 +37,6 @@ export async function init(filePath, refresh) {
4037
try {
4138
// 读取文件内容
4239
const fileContent = await readFile(filePath, 'utf-8');
43-
4440
// 计算文件的 hash 值
4541
const fileHash = computeHash(fileContent);
4642

@@ -59,6 +55,7 @@ export async function init(filePath, refresh) {
5955
sleep,
6056
sleepSync,
6157
utils,
58+
computeHash,
6259
}
6360
const drpySanbox = {
6461
jsp,
@@ -101,7 +98,13 @@ export async function init(filePath, refresh) {
10198

10299
// 创建一个沙箱上下文,注入需要的全局变量和函数
103100
const sandbox = {
104-
console,
101+
console, // 将 console 注入沙箱,便于调试
102+
setTimeout, // 注入定时器方法
103+
setInterval,
104+
clearTimeout,
105+
clearInterval,
106+
module: {}, // 模块支持
107+
exports: {}, // 模块支持
105108
rule: {}, // 用于存放导出的 rule 对象
106109
...utilsSanbox,
107110
...drpySanbox,
@@ -111,12 +114,63 @@ export async function init(filePath, refresh) {
111114
// 创建一个上下文
112115
const context = vm.createContext(sandbox);
113116

117+
// 注入扩展代码到沙箱中
118+
const polyfillsScript = new vm.Script(es6_extend_code);
119+
polyfillsScript.runInContext(context);
120+
114121
// 执行文件内容,将其放入沙箱中
115122
const script = new vm.Script(fileContent);
116123
script.runInContext(context);
117124

118125
// 访问沙箱中的 rule 对象
119126
const moduleObject = utils.deepCopy(sandbox.rule);
127+
moduleObject.injectMethodVars = async function (method, args, vars) {
128+
async function _inner() {
129+
let input;
130+
let MY_URL;
131+
// 遍历 vars 对象,将其中的键值对转化为局部变量
132+
for (let key in vars) {
133+
let value = vars[key];
134+
135+
// 根据类型判断并转化值
136+
if (value === undefined) {
137+
value = 'undefined'; // undefined转为 'undefined'
138+
} else if (value === null) {
139+
value = 'null'; // null 转为 'null'
140+
} else if (value === '') {
141+
value = "''"; // 空字符串转为 "''"
142+
} else if (typeof value === 'boolean') {
143+
value = value ? 'true' : 'false'; // 布尔值转为 'true' 或 'false'
144+
} else if (typeof value === 'object') {
145+
if (Array.isArray(value)) {
146+
value = JSON.stringify(value); // 数组转为 JSON 字符串
147+
} else if (value instanceof Date) {
148+
value = `new Date("${value.toISOString()}")`; // Date 对象转为日期字符串
149+
} else if (value instanceof RegExp) {
150+
value = value.toString(); // 正则表达式转为字符串表示
151+
} else {
152+
value = JSON.stringify(value); // 普通对象转为 JSON 字符串
153+
}
154+
}
155+
156+
// 构造赋值代码,并通过 eval 动态执行
157+
let _code = `${key} = ${value}`;
158+
console.log(_code); // 打印每个注入的变量代码
159+
eval(_code); // 使用 eval 在当前作用域中定义变量
160+
}
161+
162+
// 打印 inject 的变量值,确保它们在 eval 中被正确注入
163+
console.log('=====inject vars=====');
164+
console.log(input); // 现在 input 应该是定义好的
165+
console.log(MY_URL); // MY_URL 应该被注入并可用
166+
167+
// 执行传入的 method
168+
return await method(...args);
169+
}
170+
171+
return await _inner();
172+
};
173+
120174

121175
// 检查并执行 `预处理` 方法
122176
if (typeof moduleObject.预处理 === 'function') {
@@ -129,7 +183,7 @@ export async function init(filePath, refresh) {
129183

130184
// 缓存模块和文件的 hash 值
131185
moduleCache.set(filePath, {moduleObject, hash: fileHash});
132-
186+
console.log(moduleObject);
133187
return moduleObject;
134188
} catch (error) {
135189
console.error('Error in drpy.init:', error);
@@ -142,43 +196,62 @@ export async function init(filePath, refresh) {
142196
* 调用模块的指定方法
143197
* @param {string} filePath - 模块文件路径
144198
* @param {string} method - 要调用的属性方法名称
145-
* @param args
199+
* @param args - 传递给方法的普通参数
200+
* @param {object} injectVars - 需要注入的变量(如 input 和 MY_URL)
146201
* @returns {Promise<any>} - 方法调用的返回值
147202
*/
148-
async function invokeMethod(filePath, method, ...args) {
203+
async function invokeMethod(filePath, method, args = [], injectVars = {}) {
149204
const moduleObject = await init(filePath); // 确保模块已初始化
205+
150206
if (moduleObject[method] && typeof moduleObject[method] === 'function') {
151-
return await moduleObject[method](...args); // 调用对应的方法并传递参数
207+
return await moduleObject.injectMethodVars(moduleObject[method], args, injectVars);
208+
// return await moduleObject[method](...args); // 调用对应的方法并传递参数
152209
} else {
153210
throw new Error(`Method ${method} not found in module ${filePath}`);
154211
}
155212
}
156213

157-
// 各种接口调用方法
158-
159-
export async function home(filePath, filter = 1) {
160-
return await invokeMethod(filePath, 'class_parse', {filter});
214+
export async function home(filePath, filter = 1, inputValue, urlValue) {
215+
return await invokeMethod(filePath, 'class_parse', [filter], {
216+
input: inputValue || '',
217+
MY_URL: urlValue || ''
218+
});
161219
}
162220

163-
export async function homeVod(filePath) {
164-
return await invokeMethod(filePath, '推荐');
221+
export async function homeVod(filePath, inputValue, urlValue) {
222+
return await invokeMethod(filePath, '推荐', [], {
223+
input: inputValue || '',
224+
MY_URL: urlValue || ''
225+
});
165226
}
166227

167-
export async function cate(filePath, tid, pg = 1, filter = 1, extend = {}) {
168-
return await invokeMethod(filePath, '一级', {tid, pg, filter, extend});
228+
export async function cate(filePath, tid, pg = 1, filter = 1, extend = {}, inputValue, urlValue) {
229+
return await invokeMethod(filePath, '一级', [tid, pg, filter, extend], {
230+
input: inputValue || '',
231+
MY_URL: urlValue || ''
232+
});
169233
}
170234

171-
export async function detail(filePath, ids) {
235+
export async function detail(filePath, ids, inputValue, urlValue) {
172236
if (!Array.isArray(ids)) throw new Error('Parameter "ids" must be an array');
173-
return await invokeMethod(filePath, '二级', {ids});
237+
return await invokeMethod(filePath, '二级', [ids], {
238+
input: inputValue || '',
239+
MY_URL: urlValue || ''
240+
});
174241
}
175242

176-
export async function search(filePath, wd, quick = 0, pg = 1) {
177-
return await invokeMethod(filePath, '搜索', {wd, quick, pg});
243+
export async function search(filePath, wd, quick = 0, pg = 1, inputValue, urlValue) {
244+
return await invokeMethod(filePath, '搜索', [wd, quick, pg], {
245+
input: inputValue || '',
246+
MY_URL: urlValue || ''
247+
});
178248
}
179249

180-
export async function play(filePath, flag, id, flags) {
250+
export async function play(filePath, flag, id, flags, inputValue, urlValue) {
181251
flags = flags || [];
182252
if (!Array.isArray(flags)) throw new Error('Parameter "flags" must be an array');
183-
return await invokeMethod(filePath, 'lazy', {flag, id, flags});
253+
return await invokeMethod(filePath, 'lazy', [flag, id, flags], {
254+
input: inputValue || '',
255+
MY_URL: urlValue || ''
256+
});
184257
}

0 commit comments

Comments
 (0)