drpyCustom.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. globalThis.MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36';
  2. globalThis.PC_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36';
  3. globalThis.UA = 'Mozilla/5.0';
  4. globalThis.UC_UA = 'Mozilla/5.0 (Linux; U; Android 9; zh-CN; MI 9 Build/PKQ1.181121.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.5.1035 Mobile Safari/537.36';
  5. globalThis.IOS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1';
  6. globalThis.RULE_CK = 'cookie'; // 源cookie的key值
  7. globalThis.CATE_EXCLUDE = '首页|留言|APP|下载|资讯|新闻|动态';
  8. globalThis.TAB_EXCLUDE = '猜你|喜欢|下载|剧情|榜|评论';
  9. globalThis.OCR_RETRY = 3;//ocr验证重试次数
  10. globalThis.OCR_API = 'https://api.nn.ci/ocr/b64/text';//ocr在线识别接口
  11. globalThis.nodata = {
  12. list: [{
  13. vod_name: '无数据,防无限请求',
  14. vod_id: 'no_data',
  15. vod_remarks: '不要点,会崩的',
  16. vod_pic: 'https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/404.jpg'
  17. }],
  18. total: 1, pagecount: 1, page: 1, limit: 1
  19. };
  20. globalThis.SPECIAL_URL = /^(ftp|magnet|thunder|ws):/;
  21. globalThis.是否正版 = function (vipUrl) {
  22. let flag = new RegExp('qq\.com|iqiyi\.com|youku\.com|mgtv\.com|bilibili\.com|sohu\.com|ixigua\.com|pptv\.com|miguvideo\.com|le\.com|1905\.com|fun\.tv');
  23. return flag.test(vipUrl);
  24. }
  25. globalThis.urlDeal = function (vipUrl) {
  26. if (!vipUrl) {
  27. return ''
  28. }
  29. if (!是否正版(vipUrl)) {
  30. return vipUrl
  31. }
  32. if (!/miguvideo/.test(vipUrl)) {
  33. vipUrl = vipUrl.split('#')[0].split('?')[0];
  34. }
  35. return vipUrl
  36. }
  37. /**
  38. * 判断是否需要解析
  39. * @param url
  40. * @returns {number|number}
  41. */
  42. function tellIsJx(url) {
  43. try {
  44. let is_vip = !/\.(m3u8|mp4|m4a)$/.test(url.split('?')[0]) && 是否正版(url);
  45. return is_vip ? 1 : 0
  46. } catch (e) {
  47. return 1
  48. }
  49. }
  50. globalThis.tellIsJx = tellIsJx;
  51. globalThis.setResult = function (d) {
  52. if (!Array.isArray(d)) {
  53. return []
  54. }
  55. let vods = [];
  56. d.forEach(function (it) {
  57. let obj = {
  58. vod_id: it.url || '',
  59. vod_name: it.title || '',
  60. vod_remarks: it.desc || '',
  61. vod_content: it.content || '',
  62. vod_pic: it.pic_url || it.img || '',
  63. };
  64. let keys = Object.keys(it);
  65. if (keys.includes('tname')) {
  66. obj.type_name = it.tname || '';
  67. }
  68. if (keys.includes('tid')) {
  69. obj.type_id = it.tid || '';
  70. }
  71. if (keys.includes('year')) {
  72. obj.vod_year = it.year || '';
  73. }
  74. if (keys.includes('actor')) {
  75. obj.vod_actor = it.actor || '';
  76. }
  77. if (keys.includes('director')) {
  78. obj.vod_director = it.director || '';
  79. }
  80. if (keys.includes('area')) {
  81. obj.vod_area = it.area || '';
  82. }
  83. vods.push(obj);
  84. });
  85. return vods
  86. }
  87. globalThis.setResult2 = function (res) {
  88. return res.list || []
  89. }
  90. globalThis.setHomeResult = function (res) {
  91. if (!res || typeof (res) !== 'object') {
  92. return []
  93. }
  94. return setResult(res.list);
  95. }
  96. /**
  97. * 将base64编码进行url编译
  98. * @param str
  99. * @returns {string}
  100. */
  101. globalThis.urlencode = function (str) {
  102. str = (str + '').toString();
  103. return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
  104. }
  105. /**
  106. * url编码,同 encodeURI
  107. * @param str
  108. * @returns {string}
  109. */
  110. globalThis.encodeUrl = function (str) {
  111. if (typeof (encodeURI) == 'function') {
  112. return encodeURI(str)
  113. } else {
  114. str = (str + '').toString();
  115. return encodeURIComponent(str).replace(/%2F/g, '/').replace(/%3F/g, '?').replace(/%3A/g, ':').replace(/%40/g, '@').replace(/%3D/g, '=').replace(/%3A/g, ':').replace(/%2C/g, ',').replace(/%2B/g, '+').replace(/%24/g, '$');
  116. }
  117. }
  118. globalThis.uint8ArrayToBase64 = function (uint8Array) {
  119. let binaryString = String.fromCharCode.apply(null, Array.from(uint8Array));
  120. return btoa(binaryString);
  121. }
  122. globalThis.Utf8ArrayToStr = function (array) {
  123. var out, i, len, c;
  124. var char2, char3;
  125. out = "";
  126. len = array.length;
  127. i = 0;
  128. while (i < len) {
  129. c = array[i++];
  130. switch (c >> 4) {
  131. case 0:
  132. case 1:
  133. case 2:
  134. case 3:
  135. case 4:
  136. case 5:
  137. case 6:
  138. case 7:
  139. out += String.fromCharCode(c);
  140. break;
  141. case 12:
  142. case 13:
  143. char2 = array[i++];
  144. out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
  145. break;
  146. case 14:
  147. char2 = array[i++];
  148. char3 = array[i++];
  149. out += String.fromCharCode(
  150. ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0)
  151. );
  152. break;
  153. }
  154. }
  155. return out;
  156. }
  157. /**
  158. * gzip压缩base64|压缩率80%+
  159. * @param str
  160. * @returns {string}
  161. */
  162. globalThis.gzip = function (str) {
  163. let arr = pako.gzip(str, {
  164. // to: 'string'
  165. });
  166. return uint8ArrayToBase64(arr)
  167. }
  168. /**
  169. * gzip解压base64数据
  170. * @param b64Data
  171. * @returns {string}
  172. */
  173. globalThis.ungzip = function (b64Data) {
  174. let strData = atob(b64Data);
  175. const charData = strData.split('').map(function (x) {
  176. return x.charCodeAt(0);
  177. });
  178. const binData = new Uint8Array(charData);
  179. const data = pako.inflate(binData);
  180. return Utf8ArrayToStr(data);
  181. }
  182. /**
  183. * 字符串按指定编码
  184. * @param input
  185. * @param encoding
  186. * @returns {*}
  187. */
  188. globalThis.encodeStr = function (input, encoding) {
  189. encoding = encoding || 'gbk';
  190. if (encoding.startsWith('gb')) {
  191. const strTool = gbkTool();
  192. input = strTool.encode(input);
  193. }
  194. return input
  195. }
  196. /**
  197. * 字符串指定解码
  198. * @param input
  199. * @param encoding
  200. * @returns {*}
  201. */
  202. globalThis.decodeStr = function (input, encoding) {
  203. encoding = encoding || 'gbk';
  204. if (encoding.startsWith('gb')) {
  205. const strTool = gbkTool();
  206. input = strTool.decode(input);
  207. }
  208. return input
  209. }
  210. globalThis.getCryptoJS = function () {
  211. // return request('https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/libs/crypto-hiker.js');
  212. return 'console.log("CryptoJS已装载");'
  213. }
  214. // 封装的RSA加解密类
  215. globalThis.RSA = {
  216. decode: function (data, key, option) {
  217. option = option || {};
  218. if (typeof (JSEncrypt) === 'function') {
  219. let chunkSize = option.chunkSize || 117; // 默认分段长度为117
  220. let privateKey = this.getPrivateKey(key); // 获取私钥
  221. const decryptor = new JSEncrypt(); //创建解密对象实例
  222. decryptor.setPrivateKey(privateKey); //设置秘钥
  223. let uncrypted = '';
  224. // uncrypted = decryptor.decrypt(data);
  225. uncrypted = decryptor.decryptUnicodeLong(data);
  226. return uncrypted;
  227. } else {
  228. return false
  229. }
  230. },
  231. encode: function (data, key, option) {
  232. option = option || {};
  233. if (typeof (JSEncrypt) === 'function') {
  234. let chunkSize = option.chunkSize || 117; // 默认分段长度为117
  235. let publicKey = this.getPublicKey(key); // 获取公钥
  236. const encryptor = new JSEncrypt();
  237. encryptor.setPublicKey(publicKey); // 设置公钥
  238. let encrypted = ''; // 加密结果
  239. // const textLen = data.length; // 待加密文本长度
  240. // let offset = 0; // 分段偏移量
  241. // // 分段加密
  242. // while (offset < textLen) {
  243. // let chunk = data.slice(offset, chunkSize); // 提取分段数据
  244. // let enc = encryptor.encrypt(chunk); // 加密分段数据
  245. // encrypted += enc; // 连接加密结果
  246. // offset += chunkSize; // 更新偏移量
  247. // }
  248. encrypted = encryptor.encryptUnicodeLong(data);
  249. return encrypted
  250. } else {
  251. return false
  252. }
  253. },
  254. fixKey(key, prefix, endfix) {
  255. if (!key.includes(prefix)) {
  256. key = prefix + key;
  257. }
  258. if (!key.includes(endfix)) {
  259. key += endfix
  260. }
  261. return key
  262. },
  263. getPrivateKey(key) {
  264. let prefix = '-----BEGIN RSA PRIVATE KEY-----';
  265. let endfix = '-----END RSA PRIVATE KEY-----';
  266. return this.fixKey(key, prefix, endfix);
  267. },
  268. getPublicKey(key) {
  269. let prefix = '-----BEGIN PUBLIC KEY-----';
  270. let endfix = '-----END PUBLIC KEY-----';
  271. return this.fixKey(key, prefix, endfix);
  272. }
  273. };
  274. /**
  275. * 智能对比去除广告。支持嵌套m3u8。只需要传入播放地址
  276. * @param m3u8_url m3u8播放地址
  277. * @param headers 自定义访问m3u8的请求头,可以不传
  278. * @returns {string}
  279. */
  280. globalThis.fixAdM3u8Ai = async function (m3u8_url, headers) {
  281. let ts = (new Date).getTime();
  282. let option = headers ? {
  283. headers: headers
  284. } : {};
  285. function b(s1, s2) {
  286. let i = 0;
  287. while (i < s1.length) {
  288. if (s1[i] !== s2[i]) {
  289. break
  290. }
  291. i++
  292. }
  293. return i
  294. }
  295. function reverseString(str) {
  296. return str.split("").reverse().join("")
  297. }
  298. let m3u8 = (await req(m3u8_url, option)).content;
  299. m3u8 = m3u8.trim().split("\n").map(it => it.startsWith("#") ? it : urljoin(m3u8_url, it)).join("\n");
  300. m3u8 = m3u8.replace(/\n\n/gi, "\n");
  301. let last_url = m3u8.split("\n").slice(-1)[0];
  302. if (last_url.length < 5) {
  303. last_url = m3u8.split("\n").slice(-2)[0]
  304. }
  305. if (last_url.includes(".m3u8") && last_url !== m3u8_url) {
  306. m3u8_url = urljoin(m3u8_url, last_url);
  307. log("嵌套的m3u8_url:" + m3u8_url);
  308. m3u8 = (await req(m3u8_url, option)).content;
  309. }
  310. let s = m3u8.trim().split("\n").filter(it => it.trim()).join("\n");
  311. let ss = s.split("\n");
  312. let firststr = "";
  313. let maxl = 0;
  314. let kk = 0;
  315. let kkk1 = 1;
  316. let kkk2 = 0;
  317. let secondstr = "";
  318. for (let i = 0; i < ss.length; i++) {
  319. let s = ss[i];
  320. if (!s.startsWith("#")) {
  321. if (kk == 0)
  322. firststr = s;
  323. if (kk > 0) {
  324. if (maxl > b(firststr, s) + 1) {
  325. if (secondstr.length < 5)
  326. secondstr = s;
  327. kkk2++
  328. } else {
  329. maxl = b(firststr, s);
  330. kkk1++
  331. }
  332. }
  333. kk++;
  334. if (kk >= 30)
  335. break
  336. }
  337. }
  338. if (kkk2 > kkk1)
  339. firststr = secondstr;
  340. let firststrlen = firststr.length;
  341. let ml = Math.round(ss.length / 2).toString().length;
  342. let maxc = 0;
  343. let laststr = ss.toReversed().find(x => {
  344. if (!x.startsWith("#")) {
  345. let k = b(reverseString(firststr), reverseString(x));
  346. maxl = b(firststr, x);
  347. maxc++;
  348. if (firststrlen - maxl <= ml + k || maxc > 10) {
  349. return true
  350. }
  351. }
  352. return false
  353. }
  354. );
  355. log("最后一条切片:" + laststr);
  356. let ad_urls = [];
  357. for (let i = 0; i < ss.length; i++) {
  358. let s = ss[i];
  359. if (!s.startsWith("#")) {
  360. if (b(firststr, s) < maxl) {
  361. ad_urls.push(s);
  362. ss.splice(i - 1, 2);
  363. i = i - 2
  364. } else {
  365. ss[i] = urljoin(m3u8_url, s)
  366. }
  367. } else {
  368. ss[i] = s.replace(/URI=\"(.*)\"/, 'URI="' + urljoin(m3u8_url, "$1") + '"')
  369. }
  370. }
  371. log("处理的m3u8地址:" + m3u8_url);
  372. log("----广告地址----");
  373. log(ad_urls);
  374. m3u8 = ss.join("\n");
  375. log("处理耗时:" + ((new Date).getTime() - ts).toString());
  376. log(m3u8);
  377. return m3u8
  378. }
  379. /**
  380. * 强制正序算法
  381. * @param lists 待正序列表
  382. * @param key 正序键
  383. * @param option 单个元素处理函数
  384. * @returns {*}
  385. */
  386. globalThis.forceOrder = function (lists, key, option) {
  387. let start = Math.floor(lists.length / 2);
  388. let end = Math.min(lists.length - 1, start + 1);
  389. if (start >= end) {
  390. return lists;
  391. }
  392. let first = lists[start];
  393. let second = lists[end];
  394. if (key) {
  395. try {
  396. first = first[key];
  397. second = second[key];
  398. } catch (e) {
  399. }
  400. }
  401. if (option && typeof (option) === 'function') {
  402. try {
  403. first = option(first);
  404. second = option(second);
  405. } catch (e) {
  406. }
  407. }
  408. first += '';
  409. second += '';
  410. // console.log(first,second);
  411. if (first.match(/(\d+)/) && second.match(/(\d+)/)) {
  412. let num1 = Number(first.match(/(\d+)/)[1]);
  413. let num2 = Number(second.match(/(\d+)/)[1]);
  414. if (num1 > num2) {
  415. lists.reverse();
  416. }
  417. }
  418. return lists
  419. }
  420. /**
  421. * 获取链接的query请求转为js的object字典对象
  422. * @param url
  423. * @returns {{}}
  424. */
  425. globalThis.getQuery = function (url) {
  426. try {
  427. if (url.indexOf('?') > -1) {
  428. url = url.slice(url.indexOf('?') + 1);
  429. }
  430. let arr = url.split("#")[0].split("&");
  431. const resObj = {};
  432. arr.forEach(item => {
  433. let arr1 = item.split("=");
  434. let key = arr1[0];
  435. let value = arr1.slice(1).join('=');
  436. resObj[key] = value;
  437. });
  438. return resObj;
  439. } catch (err) {
  440. log(`getQuery发生错误:${e.message}`)
  441. return {};
  442. }
  443. }
  444. const defaultParser = {
  445. pdfh: pdfh,
  446. pdfa: pdfa,
  447. pd: pd,
  448. };
  449. const parseTags = {
  450. jsp: {
  451. pdfh: pdfh,
  452. pdfa: pdfa,
  453. pd: pd,
  454. },
  455. json: {
  456. pdfh(html, parse) {
  457. if (!parse || !parse.trim()) {
  458. return '';
  459. }
  460. if (typeof (html) === 'string') {
  461. // print('jsonpath:pdfh字符串转dict');
  462. html = JSON.parse(html);
  463. }
  464. parse = parse.trim();
  465. if (!parse.startsWith('$.')) {
  466. parse = '$.' + parse;
  467. }
  468. parse = parse.split('||');
  469. for (let ps of parse) {
  470. let ret = cheerio.jp(ps, html);
  471. if (Array.isArray(ret)) {
  472. ret = ret[0] || '';
  473. } else {
  474. ret = ret || ''
  475. }
  476. if (ret && typeof (ret) !== 'string') {
  477. ret = ret.toString();
  478. }
  479. if (ret) {
  480. return ret
  481. }
  482. }
  483. return '';
  484. },
  485. pdfa(html, parse) {
  486. if (!parse || !parse.trim()) {
  487. return '';
  488. }
  489. if (typeof (html) === 'string') {
  490. // print('jsonpath:pdfa字符串转dict');
  491. html = JSON.parse(html);
  492. }
  493. parse = parse.trim()
  494. if (!parse.startsWith('$.')) {
  495. parse = '$.' + parse;
  496. }
  497. let ret = cheerio.jp(parse, html);
  498. if (Array.isArray(ret) && Array.isArray(ret[0]) && ret.length === 1) {
  499. return ret[0] || []
  500. }
  501. return ret || []
  502. },
  503. pd(html, parse) {
  504. let ret = parseTags.json.pdfh(html, parse);
  505. if (ret) {
  506. return urljoin(MY_URL, ret);
  507. }
  508. return ret
  509. },
  510. },
  511. jq: {
  512. pdfh(html, parse) {
  513. if (!html || !parse || !parse.trim()) {
  514. return ''
  515. }
  516. parse = parse.trim();
  517. let result = defaultParser.pdfh(html, parse);
  518. // print(`pdfh解析${parse}=>${result}`);
  519. return result;
  520. },
  521. pdfa(html, parse) {
  522. if (!html || !parse || !parse.trim()) {
  523. return [];
  524. }
  525. parse = parse.trim();
  526. let result = defaultParser.pdfa(html, parse);
  527. // print(result);
  528. print(`pdfa解析${parse}=>${result.length}`);
  529. return result;
  530. },
  531. pd(html, parse, base_url) {
  532. if (!html || !parse || !parse.trim()) {
  533. return ''
  534. }
  535. parse = parse.trim();
  536. base_url = base_url || MY_URL;
  537. return defaultParser.pd(html, parse, base_url);
  538. },
  539. },
  540. getParse(p0) {//非js开头的情况自动获取解析标签
  541. if (p0.startsWith('jsp:')) {
  542. return this.jsp
  543. } else if (p0.startsWith('json:')) {
  544. return this.json
  545. } else if (p0.startsWith('jq:')) {
  546. return this.jq
  547. } else {
  548. return this.jq
  549. }
  550. }
  551. };
  552. globalThis.stringify = JSON.stringify;
  553. // const jsp = parseTags.jsp;
  554. // const jq = parseTags.jq;
  555. /**
  556. * 处理返回的json数据
  557. * @param html
  558. * @returns {*}
  559. */
  560. globalThis.dealJson = function (html) {
  561. try {
  562. // html = html.match(/[\w|\W|\s|\S]*?(\{[\w|\W|\s|\S]*\})/).group[1];
  563. html = html.trim();
  564. if (!((html.startsWith('{') && html.endsWith('}')) || (html.startsWith('[') && html.endsWith(']')))) {
  565. html = '{' + html.match(/.*?\{(.*)\}/m)[1] + '}';
  566. }
  567. } catch (e) {
  568. }
  569. try {
  570. html = JSON.parse(html);
  571. } catch (e) {
  572. }
  573. // console.log(typeof(html));
  574. return html;
  575. }
  576. /**
  577. * 验证码识别逻辑,需要java实现(js没有bytes类型,无法调用后端的传递图片二进制获取验证码文本的接口)
  578. * @type {{api: string, classification: (function(*=): string)}}
  579. */
  580. globalThis.OcrApi = {
  581. api: OCR_API,
  582. classification: async function (img) { // img是byte类型,这里不方便搞啊
  583. let code = '';
  584. try {
  585. // let html = request(this.api,{data:{img:img},headers:{'User-Agent':PC_UA},'method':'POST'},true);
  586. // html = JSON.parse(html);
  587. // code = html.url||'';
  588. log('通过drpy_ocr验证码接口过验证...');
  589. let html = '';
  590. if (this.api.endsWith('drpy/text')) {
  591. html = (await req(this.api, {
  592. data: {img: img},
  593. headers: {'User-Agent': PC_UA},
  594. 'method': 'POST'
  595. })).content;
  596. } else {
  597. html = (await req(this.api, {body: img, headers: {'User-Agent': PC_UA}, 'method': 'POST'})).content;
  598. }
  599. code = html || '';
  600. } catch (e) {
  601. log(`OCR识别验证码发生错误:${e.message}`)
  602. }
  603. return code
  604. }
  605. };
  606. /**
  607. * 获取链接的host(带http协议的完整链接)
  608. * @param url 任意一个正常完整的Url,自动提取根
  609. * @returns {string}
  610. */
  611. globalThis.getHome = function (url) {
  612. if (!url) {
  613. return ''
  614. }
  615. let tmp = url.split('//');
  616. url = tmp[0] + '//' + tmp[1].split('/')[0];
  617. try {
  618. url = decodeURIComponent(url);
  619. } catch (e) {
  620. }
  621. return url
  622. }
  623. /**
  624. * get参数编译链接,类似python params字典自动拼接
  625. * @param url 访问链接
  626. * @param obj 参数字典
  627. * @returns {*}
  628. */
  629. globalThis.buildUrl = function (url, obj) {
  630. obj = obj || {};
  631. if (url.indexOf('?') < 0) {
  632. url += '?'
  633. }
  634. let param_list = [];
  635. let keys = Object.keys(obj);
  636. keys.forEach(it => {
  637. param_list.push(it + '=' + obj[it])
  638. });
  639. let prs = param_list.join('&');
  640. if (keys.length > 0 && !url.endsWith('?')) {
  641. url += '&'
  642. }
  643. url += prs;
  644. return url
  645. }
  646. /**
  647. * 远程依赖执行函数
  648. * @param url 远程js地址
  649. */
  650. function $require(url) {
  651. eval(request(url));
  652. }
  653. //字符串To对象
  654. globalThis.parseQueryString = function (query) {
  655. const params = {};
  656. query.split('&').forEach(function (part) {
  657. // 使用正则表达式匹配键和值,直到遇到第一个等号为止
  658. const regex = /^(.*?)=(.*)/;
  659. const match = part.match(regex);
  660. if (match) {
  661. const key = decodeURIComponent(match[1]);
  662. const value = decodeURIComponent(match[2]);
  663. params[key] = value;
  664. }
  665. });
  666. return params;
  667. }
  668. //URL需要转码字符串
  669. globalThis.encodeIfContainsSpecialChars = function (value) {
  670. // 定义在URL中需要编码的特殊字符
  671. const specialChars = ":/?#[]@!$'()*+,;=%";
  672. // 检查值中是否包含特殊字符
  673. if (specialChars.split('').some(char => value.toString().includes(char))) {
  674. // 如果包含,则使用encodeURIComponent进行编码
  675. return encodeURIComponent(value);
  676. }
  677. // 如果不包含特殊字符,返回原值
  678. return value;
  679. }
  680. //对象To字符串
  681. globalThis.objectToQueryString = function (obj) {
  682. const encoded = [];
  683. for (let key in obj) {
  684. if (obj.hasOwnProperty(key)) {
  685. encoded.push(encodeURIComponent(key) + '=' + encodeIfContainsSpecialChars(obj[key]));
  686. }
  687. }
  688. return encoded.join('&');
  689. }