-
Notifications
You must be signed in to change notification settings - Fork 285
Expand file tree
/
Copy pathdr2Adapter.js
More file actions
2088 lines (1926 loc) · 73.6 KB
/
dr2Adapter.js
File metadata and controls
2088 lines (1926 loc) · 73.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* drpy2.js - T3脚本服务端解析引擎
* 基于drpy2.min.js的官方实现,提供与drpyS相同的API接口
* 专门用于解析T3类型脚本
*
* @version 1.0.0
* @author drpy2 team
*/
import {readFile} from 'fs/promises';
import {readFileSync, writeFileSync, existsSync, mkdirSync} from 'fs';
import {fileURLToPath} from 'url';
import path, { join } from 'path';
import vm from 'vm';
// === 导入依赖库 ===
import '../libs_drpy/es6-extend.js';
import * as utils from '../utils/utils.js';
import {ENV} from '../utils/env.js';
import {base64Decode, base64Encode, md5} from '../libs_drpy/crypto-util.js';
import '../libs_drpy/drpyInject.js';
import '../libs_drpy/crypto-js.js';
import '../libs_drpy/jsencrypt.js';
import '../libs_drpy/pako.min.js';
import '../libs_drpy/json5.js';
import "../libs_drpy/jinja.js";
import '../libs_drpy/moduleLoader.js';
import template from '../libs_drpy/template.js';
import '../libs_drpy/drpyCustom.js';
import {jsonpath, jsoup} from '../libs_drpy/htmlParser.js';
import {evalFetch as fetch,req,request} from './drpy2_Inject.js';
// 全局化同步fetch函数,替换掉异步fetch
globalThis.fetch = fetch;
globalThis.req = req;
// === 基础配置和常量 ===
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const {sleep, sleepSync, deepCopy, getNowTime, urljoin,urljoin2,joinUrl,naturalSort,$js,keysToLowerCase} = utils;
const {log} = console;
// 读取扩展代码 - 优化:启动时异步初始化,避免同步堵塞
const es6JsPath = path.join(__dirname, '../libs_drpy/es6-extend.js');
const reqJsPath = path.join(__dirname, '../libs_drpy/req-extend.js');
// 使用预读取的代码内容,避免每次getSandbox都要读取
const es6_extend_code = readFileSync(es6JsPath, 'utf8');
const req_extend_code = readFileSync(reqJsPath, 'utf8');
globalThis.cheerio = {};
globalThis.cheerio.jp = function(path, jsonObject) {
try {
// 优先使用全局JSONPath
if (typeof globalThis.JSONPath !== 'undefined' && globalThis.JSONPath.JSONPath) {
return globalThis.JSONPath.JSONPath({path: path, json: jsonObject});
}
} catch (e) {
log(`cheerio.jp执行错误: ${e.message}`);
return [];
}
};
// 批量定义全局变量
function defineGlobalVariables() {
const variables = {
VODS: [],
VOD: {},
TABS: [],
LISTS: [],
MY_FL: {},
MY_CATE: ''
};
Object.entries(variables).forEach(([name, defaultValue]) => {
// 只有当全局对象上不存在该属性时才定义
if (!Object.prototype.hasOwnProperty.call(globalThis, name)) {
let privateValue = defaultValue;
Object.defineProperty(globalThis, name, {
get() { return privateValue; },
set(v) { privateValue = v; },
configurable: true,
enumerable: true
});
}
});
}
// 初始化全局变量
defineGlobalVariables();
// 常量已在drpyCustom.js中定义,这里只需要引用
const CONSTANTS = {
CATE_EXCLUDE: globalThis.CATE_EXCLUDE,
TAB_EXCLUDE: globalThis.TAB_EXCLUDE,
OCR_RETRY: globalThis.OCR_RETRY,
OCR_API: globalThis.OCR_API,
SPECIAL_URL: globalThis.SPECIAL_URL,
NO_DATA: globalThis.nodata || {
list: [{
vod_name: '无数据,防无限请求',
vod_id: 'no_data',
vod_remarks: '不要点,会崩的',
vod_pic: 'https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/404.jpg'
}],
total: 1, pagecount: 1, page: 1, limit: 1
}
};
// 全局变量
let HOST = '';
let RKEY = '';
let rule_fetch_params = {};
let fetch_params = {};
// 自动全局化MY_URL,兼容所有赋值和作用域
if (typeof globalThis.MY_URL === 'undefined') {
Object.defineProperty(globalThis, 'MY_URL', {
get() { return globalThis._MY_URL; },
set(v) { globalThis._MY_URL = v; },
configurable: true,
enumerable: true
});
}
// 自动全局化MY_FL,兼容所有赋值和作用域
if (typeof globalThis.MY_FL === 'undefined') {
Object.defineProperty(globalThis, 'MY_FL', {
get() { return globalThis._MY_FL; },
set(v) { globalThis._MY_FL = v; },
configurable: true,
enumerable: true
});
}
// 自动全局化MY_CATE,兼容所有赋值和作用域
if (typeof globalThis.MY_CATE === 'undefined') {
Object.defineProperty(globalThis, 'MY_CATE', {
get() { return globalThis._MY_CATE; },
set(v) { globalThis._MY_CATE = v; },
configurable: true,
enumerable: true
});
}
// 模块缓存 - 增加大小限制,避免内存泄漏
const moduleCache = new Map();
let homeHtmlCache = '';
let _pdfa, _pdfh, _pd; // 全局解析函数
// === 初始化模块 ===
/**
* 初始化全局环境
*/
function initGlobalEnvironment() {
// 设置全局模板
globalThis.muban = template.muban;
// 创建HTML解析函数实例并绑定方法
const jsoupInstance = new jsoup();
const pdfh = jsoupInstance.pdfh.bind(jsoupInstance);
const pdfa = jsoupInstance.pdfa.bind(jsoupInstance);
const pd = jsoupInstance.pd.bind(jsoupInstance);
// 挂载解析函数到全局
if (!globalThis.pdfh) globalThis.pdfh = pdfh;
if (!globalThis.pdfa) globalThis.pdfa = pdfa;
if (!globalThis.pd) globalThis.pd = pd;
if (!globalThis.jsp) {
globalThis.jsp = createSafeJsoup(jsoupInstance);
}
if (!globalThis.dealJson) globalThis.dealJson = dealJson;
if (!globalThis.parseTags) globalThis.parseTags = parseTags;
if (!globalThis.urljoin) globalThis.urljoin = urljoin;
if (!globalThis.urljoin2) globalThis.urljoin2 = urljoin2;
if (!globalThis.joinUrl) globalThis.joinUrl = joinUrl;
// 挂载安全的JSON解析函数到全局
if (!globalThis.safeEval) globalThis.safeEval = safeEval;
// 保存原始的JSON.parse,并替换为安全版本(可选,谨慎使用)
}
initGlobalEnvironment();
/**
* 加载WASM模块
*/
async function loadWASMModules() {
try {
if (!globalThis.CryptoJSW) {
await import('../libs_drpy/crypto-js-wasm.js');
globalThis.CryptoJSW = CryptoJSWasm;
}
log('WASM模块加载成功');
} catch (error) {
log(`WASM模块加载失败: ${error.message}`);
globalThis.CryptoJSW = {
loadAllWasm: async () => {},
...globalThis.CryptoJS
};
}
}
// === 工具函数模块 ===
/**
* 计算文件哈希值
*/
function computeHash(content) {
return md5(content);
}
// gzip解压缩函数已在drpyCustom.js中定义为globalThis.ungzip
/**
* 辅助函数 getPP
*/
function getPP(p, pn, pp, ppn) {
try {
return p[pn] === '*' && pp.length > ppn ? pp[ppn] : p[pn];
} catch (e) {
return '';
}
}
/**
* 时间统计工具
*/
function createTimer(label) {
const startTime = Date.now();
return () => {
const cost = Date.now() - startTime;
console.log(`${label}耗时:${cost}毫秒`);
return cost;
};
}
/**
* 安全的JavaScript执行函数 - 增强版
* 在执行过程中临时替换JSON.parse为安全版本
*/
function safeEval(code, context = {}) {
try {
// 确保关键变量存在
if (!globalThis.VOD) globalThis.VOD = {};
if (!globalThis.VODS) globalThis.VODS = [];
if (!globalThis.TABS) globalThis.TABS = [];
if (!globalThis.LISTS) globalThis.LISTS = [];
// 将上下文变量注入到全局
const originalVars = {};
for (const [key, value] of Object.entries(context)) {
originalVars[key] = globalThis[key];
globalThis[key] = value;
}
try {
return eval(code);
} finally {
// 恢复原始上下文变量
for (const [key, originalValue] of Object.entries(originalVars)) {
if (originalValue === undefined) {
delete globalThis[key];
} else {
globalThis[key] = originalValue;
}
}
}
} catch (e) {
console.error(`脚本执行错误: ${e.message}`, e.stack);
// 不抛出错误,保证流程继续
return null;
}
}
/**
* 创建安全的字符串对象 - 解决null调用字符串方法的问题
* 当DOM查询返回null/undefined时,提供安全的字符串方法
*/
function createSafeString(value) {
if (value === null || value === undefined) {
// 返回一个模拟字符串对象,包含常用的字符串方法
return {
toString: () => '',
valueOf: () => '',
replace: () => '',
split: () => [''],
substr: () => '',
substring: () => '',
indexOf: () => -1,
includes: () => false,
startsWith: () => false,
endsWith: () => false,
toLowerCase: () => '',
toUpperCase: () => '',
trim: () => '',
length: 0,
// 让它在字符串上下文中表现为空字符串
[Symbol.toPrimitive]: () => '',
// 确保直接使用时返回空字符串
[Symbol.toString]: () => ''
};
}
return value;
}
/**
* 创建安全的JSON对象 - 解决访问undefined属性的问题
* 当访问不存在的属性时,返回安全的默认值而不是抛出错误
*/
function createSafeJsonProxy(obj) {
if (obj === null || obj === undefined) {
// 如果对象本身就是null/undefined,返回一个安全的代理
return new Proxy({}, {
get(target, prop) {
if (prop === 'data' || typeof prop === 'string') {
return createSafeJsonProxy({});
}
return undefined;
}
});
}
if (typeof obj !== 'object') {
return obj;
}
return new Proxy(obj, {
get(target, prop) {
const value = target[prop];
if (value === null || value === undefined) {
// 如果属性不存在或为null/undefined,返回安全的代理对象
if (prop === 'data' || typeof prop === 'string') {
return createSafeJsonProxy({});
}
return undefined;
}
// 如果是对象,递归包装
if (typeof value === 'object' && value !== null) {
return createSafeJsonProxy(value);
}
return value;
}
});
}
/**
* 安全的DOM查询包装器
*/
function createSafeJsoup(jsoupInstance) {
return {
pdfh: (html, parse, baseUrl) => {
const result = jsoupInstance.pdfh(html, parse, baseUrl);
return createSafeString(result);
},
pdfa: (html, parse) => {
const result = jsoupInstance.pdfa(html, parse);
return result || [];
},
pd: (html, parse, baseUrl) => {
const result = jsoupInstance.pd(html, parse, baseUrl);
return createSafeString(result);
},
pq: jsoupInstance.pq.bind(jsoupInstance),
pj: jsoupInstance.pj.bind(jsoupInstance),
pjfa: jsoupInstance.pjfa.bind(jsoupInstance),
pjfh: jsoupInstance.pjfh.bind(jsoupInstance),
};
}
/**
* 通用URL处理函数
* @param {string} url - 要处理的URL
* @param {string} host - 主机地址
* @param {boolean} hasArray - 是否包含数组形式的URL
* @returns {string} - 处理后的URL
*/
function processRuleUrl(url, host, hasArray = false) {
if (!url || !host) return url;
if (hasArray && url.includes('[') && url.includes(']')) {
let u1 = url.split('[')[0];
let u2 = url.split('[')[1].split(']')[0];
return urljoin(host, u1) + '[' + urljoin(host, u2) + ']';
}
return urljoin(host, url);
}
/**
* 通用图片处理函数 (优化性能)
*/
function processImages(vodList, rule) {
if (!Array.isArray(vodList) || !rule) return vodList;
// 提前检查是否需要处理,避免不必要的遍历
if (!rule.图片替换 && !rule.图片来源) return vodList;
try {
// 图片替换处理
if (rule.图片替换) {
if (rule.图片替换.startsWith("js:")) {
// 限制处理的数量,避免大数组影响性能
const maxProcessCount = Math.min(vodList.length, 1000);
for (let i = 0; i < maxProcessCount; i++) {
const it = vodList[i];
try {
var input = it.vod_pic;
// 确保 jsp 对象可用,并正确绑定方法
const jsoupInstance = new jsoup();
globalThis.jsp = createSafeJsoup(jsoupInstance);
safeEval(rule.图片替换.trim().replace("js:", ""));
it.vod_pic = input;
} catch (e) {
log(`图片:${it.vod_pic}替换错误:${e.message}`);
}
}
} else if (rule.图片替换.includes("=>")) {
let [replace_from, replace_to] = rule.图片替换.split("=>");
vodList.forEach((it) => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic.replace(replace_from, replace_to);
}
});
}
}
// 图片来源处理
if (rule.图片来源) {
vodList.forEach((it) => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic + rule.图片来源;
}
});
}
} catch (e) {
log(`图片处理过程中出现错误: ${e.message}`);
}
return vodList;
}
/**
* 通用返回值处理函数
*/
function parseJsonResult(result) {
if (typeof result === 'string') {
try {
return JSON.parse(result);
} catch (e) {
log(`JSON解析失败: ${e.message}`);
return result;
}
}
return result;
}
/**
* 通用HTTP请求处理函数
*/
function makeRequest(url, options = {}) {
try {
const { method = 'get', postData = '', headers = {} } = options;
const requestHeaders = { ...fetch_params.headers, ...headers };
if (method.toLowerCase() === 'post') {
return globalThis.post(url, {
body: postData,
headers: requestHeaders
});
} else if (method.toLowerCase() === 'postjson') {
try {
const jsonData = typeof postData === 'string' ? JSON.parse(postData) : postData;
return globalThis.post(url, {
body: JSON.stringify(jsonData),
headers: { ...requestHeaders, 'Content-Type': 'application/json' }
});
} catch (e) {
return globalThis.post(url, {
body: postData,
headers: { ...requestHeaders, 'Content-Type': 'application/json' }
});
}
} else {
return globalThis.getHtml(url);
}
} catch (e) {
log(`请求失败: ${e.message}`);
return '';
}
}
/**
* 搜索关键词编码处理函数
*/
function processEncoding(wd, rule) {
try {
if (rule.search_encoding && rule.search_encoding.toLowerCase() !== 'utf-8') {
return encodeURIComponent(wd);
}
return wd;
} catch (e) {
log(`搜索编码处理失败: ${e.message}`);
return wd;
}
}
/**
* 初始化请求参数
*/
function initFetchParams() {
fetch_params = deepCopy(rule_fetch_params);
if (!fetch_params) fetch_params = {};
if (!fetch_params.headers) fetch_params.headers = {};
}
/**
* 创建沙箱环境 - 优化为与drpyS.js相似的高效模式
*/
async function getSandbox(env = {}) {
const { getProxyUrl, hostUrl, fServer } = env;
// 加载WASM模块
await loadWASMModules();
// 工具函数沙箱 - 直接使用已有变量,避免globalThis解构
const utilsSanbox = {
sleep, sleepSync, utils, misc: globalThis.misc, computeHash, deepCopy,
urljoin, urljoin2, joinUrl, naturalSort, $js,
$: globalThis.$ || {}, getNowTime, getProxyUrl, hostUrl, fServer
};
// drpy功能沙箱 - 直接引用全局函数
const drpySanbox = {
pdfh: globalThis.pdfh, pdfa: globalThis.pdfa, pd: globalThis.pd,
pjfh: globalThis.pjfh, pjfa: globalThis.pjfa, pj: globalThis.pj,
jsoup: globalThis.jsoup, req: globalThis.req, _fetch: globalThis._fetch,
request: globalThis.request, post: globalThis.post, fetch,
getCode: globalThis.getCode, getHtml: globalThis.getHtml,
local: globalThis.local, log, print: console.log
};
// 自定义功能沙箱 - 避免重复解构
const drpyCustomSanbox = {
MOBILE_UA: globalThis.MOBILE_UA, PC_UA: globalThis.PC_UA,
UC_UA: globalThis.UC_UA, IOS_UA: globalThis.IOS_UA, UA: globalThis.UA,
RULE_CK: globalThis.RULE_CK || 'cookie',
...CONSTANTS,
setResult: globalThis.setResult, setResult2: globalThis.setResult2,
setHomeResult: globalThis.setHomeResult, dealJson: globalThis.dealJson,
urlDeal: globalThis.urlDeal, tellIsJx: globalThis.tellIsJx,
urlencode: globalThis.urlencode, encodeUrl: globalThis.encodeUrl,
getHome: globalThis.getHome, buildUrl: globalThis.buildUrl,
parseQueryString: globalThis.parseQueryString,
objectToQueryString: globalThis.objectToQueryString,
encodeIfContainsSpecialChars: globalThis.encodeIfContainsSpecialChars,
base64Encode: globalThis.base64Encode, base64Decode: globalThis.base64Decode,
md5: globalThis.md5, uint8ArrayToBase64: globalThis.uint8ArrayToBase64,
Utf8ArrayToStr: globalThis.Utf8ArrayToStr, gzip: globalThis.gzip,
ungzip: globalThis.ungzip, encodeStr: globalThis.encodeStr,
decodeStr: globalThis.decodeStr, getCryptoJS: globalThis.getCryptoJS,
RSA: globalThis.RSA, fixAdM3u8Ai: globalThis.fixAdM3u8Ai,
forceOrder: globalThis.forceOrder, getQuery: globalThis.getQuery,
stringify: globalThis.stringify || JSON.stringify,
OcrApi: globalThis.OcrApi, keysToLowerCase: globalThis.keysToLowerCase,
rc: globalThis.rc, maoss: globalThis.maoss, parseTags: globalThis.parseTags
};
// 第三方库沙箱
const libsSanbox = {
CryptoJS: globalThis.CryptoJS, CryptoJSW: globalThis.CryptoJSW,
JSEncrypt: globalThis.JSEncrypt, pako: globalThis.pako,
JSON5: globalThis.JSON5, jinja, template: globalThis.template,
axios: globalThis.axios, Buffer: globalThis.Buffer,
URL: globalThis.URL, URLSearchParams: globalThis.URLSearchParams,
cheerio: globalThis.cheerio, jsonpath: globalThis.jsonpath,
ENV: globalThis.ENV
};
// 创建沙箱 - 参照drpyS.js的简洁设计
const sandbox = {
console, WebAssembly, setTimeout, setInterval, clearTimeout, clearInterval,
TextEncoder, TextDecoder, performance, module: {}, exports: {},
rule: {}, _asyncGetRule: null,
...utilsSanbox, ...drpySanbox, ...drpyCustomSanbox, ...libsSanbox
};
// 创建VM上下文
const context = vm.createContext(sandbox);
// 注入ES6扩展
try {
const polyfillsScript = new vm.Script(es6_extend_code);
polyfillsScript.runInContext(context);
} catch (e) {
log(`ES6扩展注入失败: ${e.message}`);
}
// 注入req-extend代码 - 这是关键步骤,不能删除!
try {
const reqExtendScript = new vm.Script(req_extend_code);
reqExtendScript.runInContext(context);
sandbox.request = request;
globalThis.request = request;
// 提升关键函数到全局和沙箱
const funcNames = ['getHtml', 'request', 'post', 'getCode', 'setItem', 'getItem', 'clearItem', 'getHome', 'buildUrl', 'verifyCode'];
funcNames.forEach(funcName => {
if (sandbox[funcName] && typeof sandbox[funcName] === 'function') {
globalThis[funcName] = sandbox[funcName];
}
});
// 确保从全局环境复制函数到沙箱
const globalFuncNames = ['getHome', 'buildUrl', 'parseQueryString', 'encodeIfContainsSpecialChars', 'objectToQueryString', '$require'];
globalFuncNames.forEach(funcName => {
if (globalThis[funcName] && typeof globalThis[funcName] === 'function') {
sandbox[funcName] = globalThis[funcName];
}
});
} catch (e) {
log(`req-extend代码注入失败: ${e.message}`);
}
// 设置模块加载器
try {
if (globalThis.$ && typeof globalThis.$.setSandbox === 'function') {
sandbox.$ = globalThis.$;
sandbox.$.setSandbox(sandbox);
}
} catch (e) {
log(`模块加载器设置失败: ${e.message}`);
}
return { sandbox, context };
}
// dealJson函数已在drpyCustom.js中定义为globalThis.dealJson
/**
* 验证码处理函数
*/
function verifyCode(url) {
try {
return '';
} catch (e) {
log(`验证码处理失败: ${e.message}`);
return '';
}
}
/**
* vodDeal函数 - 处理播放源排序和重命名 (优化性能)
*/
function vodDeal(vod, rule) {
if (!vod || !rule) return vod;
try {
// 线路排序
if (rule.tab_order && rule.tab_order.length > 0 && vod.vod_play_from) {
let froms = vod.vod_play_from.split('$$$');
let urls = vod.vod_play_url ? vod.vod_play_url.split('$$$') : [];
let orderedFroms = [];
let orderedUrls = [];
// 按照tab_order顺序排列
rule.tab_order.forEach((orderItem) => {
let index = froms.findIndex(from => from.includes(orderItem));
if (index !== -1) {
orderedFroms.push(froms[index]);
if (urls[index]) {
orderedUrls.push(urls[index]);
}
froms.splice(index, 1);
urls.splice(index, 1);
}
});
// 添加剩余的
orderedFroms = orderedFroms.concat(froms);
orderedUrls = orderedUrls.concat(urls);
vod.vod_play_from = orderedFroms.join('$$$');
vod.vod_play_url = orderedUrls.join('$$$');
}
// 线路重命名 - 优化性能,减少不必要的循环
if (rule.tab_rename && Object.keys(rule.tab_rename).length > 0 && vod.vod_play_from) {
let froms = vod.vod_play_from.split('$$$');
// 预编译所有重命名规则为数组,提高查找效率
const renameEntries = Object.entries(rule.tab_rename);
froms = froms.map(from => {
for (const [key, value] of renameEntries) {
if (from.includes(key)) {
return from.replace(key, value);
}
}
return from;
});
vod.vod_play_from = froms.join('$$$');
}
// 移除指定线路 - 优化性能,使用 Set 提高查找效率
if (rule.tab_remove && rule.tab_remove.length > 0 && vod.vod_play_from) {
let froms = vod.vod_play_from.split('$$$');
let urls = vod.vod_play_url ? vod.vod_play_url.split('$$$') : [];
// 将移除项转为Set,提高查找性能
const removeSet = new Set(rule.tab_remove);
// 从后往前遍历,安全删除元素
for (let i = froms.length - 1; i >= 0; i--) {
let shouldRemove = false;
for (const removeItem of removeSet) {
if (froms[i].includes(removeItem)) {
shouldRemove = true;
break;
}
}
if (shouldRemove) {
froms.splice(i, 1);
urls.splice(i, 1);
}
}
vod.vod_play_from = froms.join('$$$');
vod.vod_play_url = urls.join('$$$');
}
// 过滤线路名称 - 预编译正则表达式,避免重复创建
if (rule.tab_exclude && vod.vod_play_from) {
let froms = vod.vod_play_from.split('$$$');
let urls = vod.vod_play_url ? vod.vod_play_url.split('$$$') : [];
const excludeRegex = new RegExp(rule.tab_exclude);
for (let i = froms.length - 1; i >= 0; i--) {
if (excludeRegex.test(froms[i])) {
froms.splice(i, 1);
urls.splice(i, 1);
}
}
vod.vod_play_from = froms.join('$$$');
vod.vod_play_url = urls.join('$$$');
}
} catch (e) {
console.log(`vodDeal处理错误:${e.message}`);
}
return vod;
}
// === 解析逻辑模块 ===
/**
* 首页解析 (完整实现) - 优化正则表达式性能
*/
async function homeParse(homeObj) {
initFetchParams();
let classes = [];
// 预编译正则表达式,避免重复创建
const cateExcludeRegex = homeObj.cate_exclude ? new RegExp(homeObj.cate_exclude) : null;
if (homeObj.class_name && homeObj.class_url) {
let names = homeObj.class_name.split('&');
let urls = homeObj.class_url.split('&');
let cnt = Math.min(names.length, urls.length);
for (let i = 0; i < cnt; i++) {
classes.push({ type_id: urls[i], type_name: names[i] });
}
}
if (homeObj.class_parse) {
if (typeof homeObj.class_parse === 'function') {
// 如果是函数,直接调用
try {
let result = await homeObj.class_parse();
if (Array.isArray(result)) {
classes = result;
}
} catch (e) {
log(`调用class_parse函数失败: ${e.message}`);
}
} else if (typeof homeObj.class_parse === 'string' && homeObj.class_parse.startsWith('js:')) {
var input = homeObj.MY_URL;
try {
// 确保 jsp 对象可用,并正确绑定方法
const jsoupInstance = new jsoup();
globalThis.jsp = createSafeJsoup(jsoupInstance);
safeEval(homeObj.class_parse.replace('js:', ''));
if (Array.isArray(input)) {
classes = input;
}
} catch (e) {
log(`通过js动态获取分类发生了错误:${e.message}`);
}
} else {
let p = homeObj.class_parse.split(';');
let p0 = p[0];
let _ps = parseTags.getParse(p0);
let is_json = p0.startsWith('json:');
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
MY_URL = homeObj.MY_URL; // 添加缺失的MY_URL设置
if (is_json) {
try {
let cms_cate_url = homeObj.MY_URL.replace('ac=detail', 'ac=list');
let html = homeObj.home_html || await globalThis.getHtml(cms_cate_url);
if (html) {
if (cms_cate_url === homeObj.MY_URL) {
homeHtmlCache = html; // 添加缺失的homeHtmlCache处理
}
html = dealJson(html);
let list = _pdfa(html, p0.replace('json:', ''));
if (list && list.length > 0) {
classes = list;
}
}
} catch (e) {
console.log(e.message);
}
} else if (p.length >= 3 && !is_json) {
try {
let html = homeObj.home_html || await globalThis.getHtml(homeObj.MY_URL);
if (html) {
homeHtmlCache = html; // 添加缺失的homeHtmlCache处理
let list = _pdfa(html, p0);
if (list && list.length > 0) {
// 预编译可能的正则表达式,避免在循环中重复创建
const urlRegex = p.length > 3 && p[3] && !homeObj.home_html ? new RegExp(p[3]) : null;
list.forEach((it, idex) => {
try {
let name = _pdfh(it, p[1]);
if (cateExcludeRegex && cateExcludeRegex.test(name)) {
return;
}
let url = _pd(it, p[2]);
if (urlRegex) {
url = url.match(urlRegex)[1];
}
classes.push({ type_id: url.trim(), type_name: name.trim() });
} catch (e) {
console.log(`分类列表定位第${idex}个元素正常报错:${e.message}`);
}
});
}
}
} catch (e) {
log(e.message);
}
}
}
}
// 使用预编译的正则表达式
classes = classes.filter(
(it) => !cateExcludeRegex || !cateExcludeRegex.test(it.type_name)
);
let resp = { class: classes };
if (homeObj.filter) {
resp.filters = homeObj.filter;
}
// 优化日志输出,避免大对象序列化影响性能
console.log(`首页解析完成,共${classes.length}个分类`);
return resp;
}
/**
* 推荐内容解析 (完整实现)
*/
async function homeVodParse(homeVodObj, rule) {
const timer = createTimer('加载首页推荐');
initFetchParams();
let d = [];
let MY_URL = homeVodObj.homeUrl;
let p = homeVodObj.推荐;
if (p === '*' && homeVodObj.一级) {
p = homeVodObj.一级;
homeVodObj.double = false;
}
if (!p || typeof p !== 'string') {
return "{}";
}
p = p.trim();
let pp = homeVodObj.一级 ? homeVodObj.一级.split(';') : [];
if (p.startsWith('js:')) {
const TYPE = 'home';
var input = MY_URL;
HOST = homeVodObj.host;
// 重置VODS,确保干净的执行环境
globalThis.VODS = [];
// 确保 jsp 对象可用,并正确绑定方法
const jsoupInstance = new jsoup();
globalThis.jsp = createSafeJsoup(jsoupInstance);
safeEval(p.replace('js:', ''));
// 获取脚本执行后的结果
d = globalThis.VODS && globalThis.VODS.length > 0 ? globalThis.VODS : d;
} else {
p = p.split(';');
if (!homeVodObj.double && p.length < 5) {
return "{}";
}else if (homeVodObj.double && p.length < 6) {
return "{}";
}
let p0 = getPP(p, 0, pp, 0);
let _ps = parseTags.getParse(p0);
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
let is_json = p0.startsWith('json:');
p0 = p0.replace(/^(jsp:|json:|jq:)/, '');
let html = homeVodObj.home_html || await globalThis.getHtml(MY_URL);
//console.log(`首页推荐解析URL:${MY_URL},html:`,html);
if (is_json) {
html = dealJson(html);
}
try {
if (homeVodObj.double) {
let items = _pdfa(html, p0);
let p1 = p[1];
let p2 = getPP(p, 2, pp, 1);
let p3 = getPP(p, 3, pp, 2);
let p4 = getPP(p, 4, pp, 3);
let p5 = getPP(p, 5, pp, 4);
let p6 = getPP(p, 6, pp, 5);
for (let item of items) {
let items2 = _pdfa(item, p1);
for (let item2 of items2) {
try {
let title = _pdfh(item2, p2);
let img = '';
try { img = _pd(item2, p3); } catch (e) {}
let desc = '';
try { desc = _pdfh(item2, p4); } catch (e) {}
let links = [];
for (let _p5 of p5.split('+')) {
let link = !homeVodObj.detailUrl ? _pd(item2, _p5, MY_URL) : _pdfh(item2, _p5);
links.push(link);
}
let content;
if (p.length > 6 && p[6]) {
content = _pdfh(item2, p6);
} else {
content = "";
}
let vid = links.join('$');
if (rule.二级 === "*") {
vid = vid + "@@" + title + "@@" + img;
}
d.push({vod_name: title, vod_pic: img, vod_remarks: desc,vod_content: content,vod_id: vid});
} catch (e) {console.log(`首页列表双层定位处理发生错误:${e.message}`);}
}
}
} else {
let items = _pdfa(html, p0);
let p1 = getPP(p, 1, pp, 1);
let p2 = getPP(p, 2, pp, 2);
let p3 = getPP(p, 3, pp, 3);
let p4 = getPP(p, 4, pp, 4);
let p5 = getPP(p, 5, pp, 5);
for (let item of items) {
try {
let title = _pdfh(item, p1);
let img = '';
try { img = _pd(item, p2, MY_URL); } catch (e) {}
let desc = '';
try { desc = _pdfh(item, p3); } catch (e) {}
let links = [];
for (let _p5 of p4.split('+')) {
let link = !homeVodObj.detailUrl ? _pd(item, _p5, MY_URL) : _pdfh(item, _p5);
links.push(link);
}
let content = p.length > 5 && p[5] ? _pdfh(item, p5) : '';
let vid = links.join('$');
if (rule.二级 === "*") {
vid = vid + "@@" + title + "@@" + img;
}
d.push({ vod_name: title, vod_pic: img, vod_remarks: desc, vod_content: content,vod_id: vid });
} catch (e) { console.log(`首页列表单层定位发生错误:${e.message}`);}
}
}
} catch (e) {}
}
// 使用通用图片处理函数
d = processImages(d, rule);
timer();
// 结果预览打印
if (d.length > 0) {
// print(d.slice(0, 2));
}
return JSON.stringify({ list: d });
}
/**
* 分类内容解析
*/
async function categoryParse(cateObj, rule) {
log(`category`);
const timer = createTimer('加载分类');