diff --git a/README.md b/README.md index 8b3ba5d..97a13b5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # drpyS(drpy-node) nodejs作为服务端的drpy实现。全面升级异步写法 -~~积极开发中,每日一更~~,当前进度 `48%` +~~积极开发中,每日一更~~,当前进度 `49%` 找工作中,随缘更新 * [本地配置接口-动态本地](/config?pwd=) @@ -19,6 +19,10 @@ nodejs作为服务端的drpy实现。全面升级异步写法 ## 更新记录 +### 20250310 + +更新至V1.1.23 + ### 20250227 更新至V1.1.22 diff --git a/docs/updateRecord.md b/docs/updateRecord.md index 2c1f28e..1acf857 100644 --- a/docs/updateRecord.md +++ b/docs/updateRecord.md @@ -1,5 +1,12 @@ # drpyS更新记录 +### 20250310 + +更新至V1.1.23 + +1. 修复番茄小说 +2. 新增2个源 + ### 20250227 更新至V1.1.22 diff --git a/js/gaze.js b/js/gaze.js new file mode 100644 index 0000000..c210c0e --- /dev/null +++ b/js/gaze.js @@ -0,0 +1,591 @@ +globalThis.window = globalThis.global = globalThis; + +class Go { + constructor() { + let s = new TextEncoder("utf-8"), + i = new TextDecoder("utf-8"), + r = new DataView(new ArrayBuffer(8)); + var o = []; + + this._callbackTimeouts = new Map(); + this._nextCallbackTimeoutID = 1; + let e = () => new DataView(this._inst.exports.m.buffer); + let t = (e) => { + r.setBigInt64(0, e, !0); + let t = r.getFloat64(0, !0); + if (0 === t) return; + if (!isNaN(t)) return t; + let n = 4294967295n & e; + return this._values[n]; + }; + let n = (n) => { + let s = e().getBigUint64(n, !0); + return t(s); + }; + let l = (e) => { + if ("number" == typeof e) + return isNaN(e) + ? 2146959360n << 32n + : 0 === e + ? (2146959360n << 32n) | 1n + : (r.setFloat64(0, e, !0), r.getBigInt64(0, !0)); + switch (e) { + case void 0: + return 0n; + case null: + return (2146959360n << 32n) | 2n; + case !0: + return (2146959360n << 32n) | 3n; + case !1: + return (2146959360n << 32n) | 4n; + } + let t = this._ids.get(e); + void 0 === t && + (void 0 === (t = this._idPool.pop()) && + (t = BigInt(this._values.length)), + (this._values[t] = e), + (this._goRefCounts[t] = 0), + this._ids.set(e, t)), + this._goRefCounts[t]++; + let n = 1n; + switch (typeof e) { + case "string": + n = 2n; + break; + case "symbol": + n = 3n; + break; + case "function": + n = 4n; + } + return t | ((2146959360n | n) << 32n); + }; + let a = (t, n) => { + let s = l(n); + e().setBigUint64(t, s, !0); + }; + let c = (e, t, n) => new Uint8Array(this._inst.exports.m.buffer, e, t); + let $ = (e, t, s) => { + let i = Array(t); + for (let r = 0; r < t; r++) i[r] = n(e + 8 * r); + return i; + }; + let d = (e, t) => i.decode(new DataView(this._inst.exports.m.buffer, e, t)); + let u = Date.now() - performance.now(); + this.importObject = { + wasi_snapshot_preview1: { + fd_write: function (t, n, s, r) { + let l = 0; + if (1 == t) + for (let a = 0; a < s; a++) { + let c = n + 8 * a, + $ = e().getUint32(c + 0, !0), + d = e().getUint32(c + 4, !0); + l += d; + for (let u = 0; u < d; u++) { + let f = e().getUint8($ + u); + if (13 == f); + else if (10 == f) { + let h = i.decode(new Uint8Array(o)); + (o = []), console.log(h); + } else o.push(f); + } + } + else console.error("invalid file descriptor:", t); + return e().setUint32(r, l, !0), 0; + }, + fd_close: () => 0, + fd_fdstat_get: () => 0, + fd_seek: () => 0, + proc_exit(e) { + if (globalThis.process) process.exit(e); + else throw "trying to exit with code " + e; + }, + random_get: (e, t) => (crypto.getRandomValues(c(e, t)), 0), + }, + a: { + "runtime.ticks": () => u + performance.now(), + "runtime.sleepTicks": (e) => { + setTimeout(this._inst.exports.t, e); + }, + d(e) { + console.error("d not implemented"); + }, + e(e, t) { + let n = d(e, t); + return l(n); + }, + a(e, n, s) { + let i = d(n, s), + r = t(e), + o = Reflect.get(r, i); + return l(o); + }, + f(e, n, s, i) { + let r = t(e), + o = d(n, s), + l = t(i); + Reflect.set(r, o, l); + }, + "syscall/js.valueDelete"(e, n, s) { + let i = t(e), + r = d(n, s); + Reflect.deleteProperty(i, r); + }, + i: (e, n) => l(Reflect.get(t(e), n)), + fIndex(e, n, s) { + Reflect.set(t(e), n, t(s)); + }, + j(n, s, i, r, o, l, c) { + let u = t(s), + f = d(i, r), + h = $(o, l, c); + try { + let g = Reflect.get(u, f); + a(n, Reflect.apply(g, u, h)), e().setUint8(n + 8, 1); + } catch (p) { + a(n, p), e().setUint8(n + 8, 0); + } + }, + "syscall/js.valueInvoke"(n, s, i, r, o) { + try { + let l = t(s), + c = $(i, r, o); + a(n, Reflect.apply(l, void 0, c)), e().setUint8(n + 8, 1); + } catch (d) { + a(n, d), e().setUint8(n + 8, 0); + } + }, + g(n, s, i, r, o) { + let l = t(s), + c = $(i, r, o); + try { + a(n, Reflect.construct(l, c)), e().setUint8(n + 8, 1); + } catch (d) { + a(n, d), e().setUint8(n + 8, 0); + } + }, + h: (e) => t(e).length, + b(n, i) { + let r = String(t(i)), + o = s.encode(r); + a(n, o), e().setInt32(n + 8, o.length, !0); + }, + c(e, n, s, i) { + let r = t(e); + c(n, s, i).set(r); + }, + "syscall/js.valueInstanceOf": (e, n) => t(e) instanceof t(n), + k(n, s, i, r, o) { + let l = n + 4, + a = c(s, i), + $ = t(o); + if (!($ instanceof Uint8Array || $ instanceof Uint8ClampedArray)) { + e().setUint8(l, 0); + return; + } + let d = $.subarray(0, a.length); + a.set(d), e().setUint32(n, d.length, !0), e().setUint8(l, 1); + }, + l(n, s, i, r, o) { + let l = n + 4, + a = t(s), + $ = c(i, r); + if (!(a instanceof Uint8Array || a instanceof Uint8ClampedArray)) { + e().setUint8(l, 0); + return; + } + let d = $.subarray(0, a.length); + a.set(d), e().setUint32(n, d.length, !0), e().setUint8(l, 1); + }, + }, + }; + this.importObject.env = this.importObject.a; + } + async run(instance) { + this._inst = instance; + this._values = [NaN, 0, null, true, false, globalThis, this]; + this._goRefCounts = []; + this._ids = new Map(); + this._idPool = []; + this.exited = false; + while (true) { + const resumePromise = new Promise((resolve) => { + this._resolveCallbackPromise = () => { + if (this.exited) { + throw new Error("bad callback: Go program has already exited"); + } + setTimeout(resolve, 0); + }; + }); + + this._inst.exports.r(); + if (this.exited) break; + + await resumePromise; + } + } + _resume() { + if (this.exited) { + throw new Error("Go program has already exited"); + } + this._inst.exports.s(); + if (this.exited) { + this._resolveExitPromise(); + } + } + _makeFuncWrapper(funcId) { + const self = this; + return function () { + const event = { + id: funcId, + this: this, + args: arguments, + }; + self._pendingEvent = event; + self._resume(); + const result = event.result; + return result; + }; + } +} + +const decryptor = (() => { + let wasmInstance = null; + let go = new Go(); + + const pedanticAe = function (buffer) { + const decompressedSync = zlib.brotliDecompressSync(buffer); + return decompressedSync; + }; + const initWASM = async (func) => { + const wasmBuffer = await fetchWASM(); + const { instance } = await WebAssembly.instantiate( + wasmBuffer, + go.importObject + ); + wasmInstance = instance; + go.run(instance); + }; + const fetchWASM = async () => { + const response = await axios.get( + "https://temp-rs-1257790209.cos.ap-chengdu.myqcloud.com/IceDespair-V2.6.svg", + { + responseType: "arraybuffer", + headers: { + "Content-Type": "application/wasm", + }, + } + ); + return pedanticAe(new Uint8Array(response.data)); + }; + const parseUrlParams = (url) => { + const params = {}; + const queryString = url.split("?")[1]; + if (!queryString) return params; + + queryString.split("-").forEach((pair) => { + const [key, value] = pair.split("="); + if (key && value) params[key] = decodeURIComponent(value); + }); + return params; + }; + const getWasmFunc = (name, mid, key) => { + return window[ + bytesToString(window["DimGive"](name, mid, decodeURIComponent(key))) + ]; + }; + const decryptDataM3u = async (bytes, sign, mid, key) => { + if (!wasmInstance) await initWASM(); + const result = getWasmFunc("nihilism", mid, key)( + bytes, + sign, + mid, + decodeURIComponent(key) + ); + return bytesToString(pedanticAe(result)); + }; + const decryptData = async (data, mid, key) => { + if (!wasmInstance) await initWASM(); + const result = getWasmFunc("8069", mid, key)( + data, + mid, + decodeURIComponent(key) + ); + return bytesToString(result); + }; + const decryptStream = async (data, mid, key, url) => { + if (!url.includes("gazes_v-@_info")) return url; + const istr = url.split("/").at(-1); + const ungzipped = pako.ungzip(data, { + to: "string", + }); + const bytes = processBytes(CryptoJS.enc.Base64.parse(ungzipped)); + const sign = CryptoJS.MD5( + `${istr}- are we anti-socialists? against the government? spies? traitor? fresh blood? no, we are just weak, sick bystanders; we just need to rot little by little with formalism until we finally become food for new shoots. ` + ) + .toString() + .substring(8, 24); + return decryptDataM3u(bytes, sign, mid, key); + }; + const processBytes = (base64Data) => { + return Uint8Array.from( + { + length: base64Data.sigBytes, + }, + (_, i) => (base64Data.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff + ); + }; + const bytesToString = (byteArray) => { + return String.fromCharCode.apply(null, byteArray); + }; + const decryptPlay = async (playUrl, src) => { + const params = parseUrlParams(playUrl); + const encryptedSrc = src; + const decryptedLink = await decryptData( + Uint8Array.from(atob(encryptedSrc), (c) => c.charCodeAt(0)), + params.mid, + params[Object.keys(params).at(-1)] + ); + return decryptedLink; + }; + const decryptM3u8 = async (playUrl, src, decryptedLink) => { + const params = parseUrlParams(playUrl); + const encryptedSrc = src; + const { data } = await axios.get(decryptedLink, { + responseType: "arraybuffer", + }); + const m3u8 = await decryptStream( + data, + params.mid, + params[Object.keys(params).at(-1)], + decryptedLink + ); + return m3u8; + }; + return { + decryptM3u8, + decryptPlay, + parseUrlParams, + }; +})(); + +var rule = { + 类型: "影视", + title: "GAZE", + desc: "源动力+L佬+秋秋+嗷呜 联合出品", + host: "https://gaze.run", + url: "/filter_movielist", + searchUrl: "/filter_movielist", + searchable: 2, + quickSearch: 0, + timeout: 5000, + play_parse: true, + filterable: 0, + class_name: "电影&剧集&番剧&国漫", + class_url: "1&2&bangumi&chinese_cartoon", + headers: { + "User-Agent": PC_UA, + Origin: "https://gaze.run", + }, + 预处理: async () => { + await rule.dealHeaders(); + }, + 推荐: async function (tid, pg, filter, extend) { + const { input, pdfa, pdfh, pd } = this; + const html = await request(input); + const d = []; + const data = pdfa(html, ".row .card"); + data.forEach((it) => { + d.push({ + title: pdfh(it, ".card-body .card-title&&Text"), + pic_url: pdfh(it, ".view img.load-imgs&&data-src"), + desc: pdfh(it, ".view .dbadge-box .badge-default&&Text"), + url: pdfh(it, ".view a&&href").replace("play/", ""), + }); + }); + return setResult(d); + }, + 一级: async function (tid, pg, filter, extend) { + const { input } = this; + const html = await request(input, { + method: "POST", + headers: { + ...this.headers, + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + data: { + mform: tid, + mcountry: "all", + "tag_arr[]": "all", + album: "all", + years: "all", + sort: "updatetime", + title: "", + page: pg, + }, + }); + const resp = JSON.parse(html); + const d = []; + resp.mlist.forEach((it) => { + d.push({ + title: it.title, + pic_url: it.cover_img, + desc: `${it.grade}|${it.definition}`, + url: it.mid, + }); + }); + return setResult(d); + }, + 二级: async function (ids) { + const { input, pdfa, pdfh, pd } = this; + const html = await request(`${this.host}/play/${ids[0]}`, { + headers: this.headers, + }); + const vod = { + vod_id: ids[0], + vod_name: pdfh(html, ".row.p-2 img&&alt"), + vod_pic: pdfh(html, ".row.p-2 img&&src"), + type_name: pdfa(html, ".row.p-2 a") + .map((it) => pdfh(it, "a&&Text")) + .join("/"), + vod_remarks: pdfh(html, ".row.p-2 h5:eq(-1)&&Text"), + vod_year: pdfh(html, ".row.p-2 a:eq(-1)&&Text"), + vod_area: pdfh(html, ".row.p-2 a:eq(-2)&&Text"), + vod_content: pdfh(html, ".row.p-2 p&&Text"), + vod_play_from: "源动力偷的线路", + vod_play_url: pdfa(html, ".col-md-12&&.sbtn-block") + .map( + (it) => + `${pdfh(it, "button--i&&Text").trim()}$${ids[0]}|${pdfh( + it, + "button&&data-src" + )}` + ) + .join("#"), + }; + return vod; + }, + 搜索: async function (wd, quick, pg) { + const { input } = this; + const html = await request(input, { + method: "POST", + headers: { + ...this.headers, + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + }, + data: { + mform: "all", + mcountry: "all", + "tag_arr[]": "all", + album: "all", + years: "all", + sort: "updatetime", + title: wd, + page: pg, + }, + }); + const resp = JSON.parse(html); + const d = []; + resp.mlist.forEach((it) => { + d.push({ + title: it.title, + pic_url: it.cover_img, + desc: `${it.grade}|${it.definition}`, + url: it.mid, + }); + }); + return setResult(d); + }, + lazy: async function (flag, id, flags) { + const { pdfa, pdfh } = this; + const [data_id, data_src] = id.split("|"); + const sourceReqUrl = `${this.host}/play/${data_id}`; + console.warn(data_id, data_src); + const source = await axios.get(sourceReqUrl, { headers: this.headers }); + const script = pdfa(source.data, "script"); + const scriptContent = script.filter((e) => + e.includes("configs-n26.1.js") + )[0]; + const sourceUrl = pdfh(scriptContent, "script&&src"); + console.warn("sourceUrl", sourceUrl); + + let play = await decryptor.decryptPlay(sourceUrl, data_src); + + if (play.includes("gazes_v-@_info")) { + return { + parse: 0, + url: + getProxyUrl() + + "&playdata=" + + encodeURIComponent(JSON.stringify([sourceUrl, data_src, play])) + + "&t=0", + }; + } else { + if (play.includes("cloud.189.cn")) { + let js_data = decryptor.parseUrlParams(sourceUrl); + const thirdKey = Object.keys(js_data)[2]; + + try { + const re_link = await axios.post( + `${this.host}/fetch_189c_murl`, + { + urls: play, + mid: js_data.mid, + }, + { + headers: { + "Content-Type": + "application/x-www-form-urlencoded; charset=UTF-8", + Accept: "*/*", + Origin: this, + [thirdKey]: encodeURIComponent(js_data[thirdKey]), + Cookie: source.headers["set-cookie"] + .map((it) => it.split(";")[0]) + .join(";"), + }, + } + ); + console.log("API Response:", re_link.data); + play = re_link.data?.url; + } catch (error) { + console.error("Request Failed:", error); + } + } + return { + parse: 0, + url: play, + }; + } + }, + proxy_rule: async function (params) { + try { + const segments = JSON.parse(decodeURIComponent(params.playdata)); + let [sourceUrl, data_src, play] = segments; + console.log(segments); + + let m3u8 = await decryptor.decryptM3u8(sourceUrl, data_src, play); + return [200, "text/text", m3u8]; + } catch (e) { + console.log(e); + } + }, + dealHeaders: async function () { + const resp = await axios.get(`${this.host}/filter`, { + headers: this.headers, + }); + // cookie 处理 + const headers = resp.headers; + const cookies = headers["set-cookie"]; + const cookie = cookies.map((item) => item.split(";")[0]).join("; "); + this.headers.Cookie = cookie; + // 请求头处理 + const html = resp.data; + const kv_macth = html.match(/'headers':({[^{}]*})/)[1]; + const kv_headers = new Function(`return ${kv_macth}`)(); + for (const key in kv_headers) { + this.headers[key] = kv_headers[key]; + } + console.warn("headers", this.headers); + }, +}; diff --git "a/js/\345\205\250\346\260\221\350\277\275\345\211\247.js" "b/js/\345\205\250\346\260\221\350\277\275\345\211\247.js" new file mode 100644 index 0000000..b563217 --- /dev/null +++ "b/js/\345\205\250\346\260\221\350\277\275\345\211\247.js" @@ -0,0 +1,107 @@ +var rule = { + 类型:'影视', + title:'全民追剧', + desc:'不告诉你', + host:'https://jenzg.cn', + url: '/index.php/vod/showfyfilter.html[/index.php/vod/showfyclass.html]', + searchUrl: '/index.php/vod/search/page/fypage/wd/**.html', + searchable:1,quickSearch:1,double:false,timeout:5000,play_parse:true,filterable:1,invalid:true, + class_name:'电影&电视剧&综艺&动漫&短剧', + class_url:'/id/61&/id/79&/id/88&/id/93&/id/99', + filter_url:'{{fl.area}}{{fl.class}}{{fl.cateId}}/page/fypage{{fl.year}}', + filter_def:{'/id/61':{cateId:'/id/61'},'/id/79':{cateId:'/id/79'},'/id/88':{cateId:'/id/88'},'/id/93':{cateId:'/id/93'},'/id/99':{cateId:'/id/99'}}, + 预处理: async () => {return []}, + 推荐: async function (tid, pg, filter, extend) { + let homeFn = rule.一级.bind(this); + return await homeFn(); + }, + 一级: async function (tid, pg, filter, extend) { + let {input, pdfa, pdfh, pd} = this; + let html = await request(input); + let d = []; + let data = pdfa(html, '.module-items .module-item'); + data.forEach((it) => { + d.push({ + title: pdfh(it, 'a&&title'), + pic_url: pd(it, 'img&&data-src'), + desc: pdfh(it, '.module-item-text&&Text'), + url: pd(it, 'a&&href'), + }) + }); + return setResult(d) + }, + 二级: async function (ids) { + let {input, pdfa, pdfh, pd} = this; + let html = await request(input); + let VOD = {}; + VOD.vod_name = pdfh(html, 'h1&&Text');//名称 + VOD.vod_actor = pdfh(html, '.video-info-items:eq(1)&&Text');//演员 + VOD.vod_director = pdfh(html, '.video-info-items:eq(0)&&Text');//导演 + VOD.vod_remarks = pdfh(html, '');//备注 + VOD.vod_status = pdfh(html, '');//状态 + VOD.vod_content = pdfh(html, '.video-info-content&&Text');//简介 + let playlist = pdfa(html, '.module-list'); + let tabs = pdfa(html, '.module-tab&&.module-tab-item.tab-item'); + let playmap = {}; + tabs.map((item, i) => { + const form = pdfh(item, 'span&&Text'); + const list = playlist[i]; + const a = pdfa(list, 'body&&a:not(:contains(排序))'); + a.map((it) => { + let title = pdfh(it, 'a&&Text'); + let urls = pd(it, 'a&&href', input); + if (!playmap.hasOwnProperty(form)) { + playmap[form] = []; + } + playmap[form].push(title + "$" + urls); + }); + }); + VOD.vod_play_from = Object.keys(playmap).join('$$$'); + const urls = Object.values(playmap); + const playUrls = urls.map((urllist) => { + return urllist.join("#"); + }); + VOD.vod_play_url = playUrls.join('$$$'); + return VOD; + }, + 搜索: async function (wd, quick, pg) { + let {input, pdfa, pdfh, pd} = this; + let html = await request(input); + let d = []; + let data = pdfa(html, '.module-items .module-search-item'); + data.forEach((it) => { + d.push({ + title: pdfh(it, 'a&&title'), + pic_url: pd(it, 'img&&data-src'), + desc: pdfh(it, '.video-serial&&Text'), + url: pd(it, 'a&&href'), + content: pdfh(it, '.video-info-aux&&Text'), + }) + }); + return setResult(d); + }, + lazy: async function (flag, id, flags) { + let {input, pdfa, pdfh, pd} = this; + let html = await request(input); + html = JSON.parse(html.match(/r player_.*?=(.*?))[1]); + let url = html.url; + if (html.encrypt == "1") { + url = unescape(url) + return {parse: 0, url: url} + } else if (html.encrypt == "2") { + url = unescape(base64Decode(url)) + return {parse: 0, url: url} + } + if (/m3u8|mp4/.test(url)) { + input = url + return {parse: 0, url: input} + } else { + return {parse: 0, url: input} + } + }, + filter: {"/id/61":[{"key":"class","name":"剧情","value":[{"n":"全部类型","v":""},{"n":"喜剧","v":"/class/喜剧"},{"n":"动作","v":"/class/动作"},{"n":"怪兽","v":"/class/怪兽"},{"n":"战争","v":"/class/战争"},{"n":"爱情","v":"/class/爱情"},{"n":"悬疑","v":"/class/悬疑"},{"n":"武侠","v":"/class/武侠"},{"n":"奇幻","v":"/class/奇幻"},{"n":"科幻","v":"/class/科幻"},{"n":"冒险","v":"/class/冒险"},{"n":"警匪","v":"/class/警匪"},{"n":"动画","v":"/class/动画"},{"n":"惊悚","v":"/class/惊悚"},{"n":"犯罪","v":"/class/犯罪"},{"n":"恐怖","v":"/class/恐怖"},{"n":"剧情","v":"/class/剧情"},{"n":"历史","v":"/class/历史"},{"n":"纪录片","v":"/class/纪录片"},{"n":"传记","v":"/class/传记"},{"n":"歌舞","v":"/class/歌舞"},{"n":"短片","v":"/class/短片"},{"n":"其他","v":"/class/其他"}]},{"key":"area","name":"地区","value":[{"n":"全部地区","v":""},{"n":"内地","v":"/area/内地"},{"n":"中国香港","v":"/area/中国香港"},{"n":"中国台湾","v":"/area/中国台湾"},{"n":"美国","v":"/area/美国"},{"n":"日本","v":"/area/日本"},{"n":"韩国","v":"/area/韩国"},{"n":"泰国","v":"/area/泰国"},{"n":"印度","v":"/area/印度"},{"n":"英国","v":"/area/英国"},{"n":"法国","v":"/area/法国"},{"n":"德国","v":"/area/德国"},{"n":"加拿大","v":"/area/加拿大"},{"n":"西班牙","v":"/area/西班牙"},{"n":"意大利","v":"/area/意大利"},{"n":"澳大利亚","v":"/area/澳大利亚"},{"n":"其它","v":"/area/其它"}]},{"key":"year","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2025","v":"/year/2025"},{"n":"2024","v":"/year/2024"},{"n":"2023","v":"/year/2023"},{"n":"2022","v":"/year/2022"},{"n":"2021","v":"/year/2021"},{"n":"2020","v":"/year/2020"},{"n":"2019","v":"/year/2019"},{"n":"2018","v":"/year/2018"},{"n":"2017","v":"/year/2017"},{"n":"2016","v":"/year/2016"},{"n":"2015","v":"/year/2015"},{"n":"2014","v":"/year/2014"},{"n":"2013","v":"/year/2013"},{"n":"2012","v":"/year/2012"},{"n":"2011","v":"/year/2011"},{"n":"2010","v":"/year/2010"},{"n":"2009","v":"/year/2009"},{"n":"2008","v":"/year/2008"},{"n":"2007","v":"/year/2007"},{"n":"2006","v":"/year/2006"},{"n":"2005","v":"/year/2005"},{"n":"2004","v":"/year/2004"}]},{"key":"by","name":"排序","value":[{"n":"时间","v":"/by/time"},{"n":"人气","v":"/by/hits"},{"n":"评分","v":"/by/score"}]}], + "/id/79":[{"key":"class","name":"类型","value":[{"n":"全部类型","v":""},{"n":"青春","v":"/class/青春"},{"n":"古装","v":"/class/古装"},{"n":"爱情","v":"/class/爱情"},{"n":"都市","v":"/class/都市"},{"n":"喜剧","v":"/class/喜剧"},{"n":"战争","v":"/class/战争"},{"n":"军旅","v":"/class/军旅"},{"n":"谍战","v":"/class/谍战"},{"n":"偶像","v":"/class/偶像"},{"n":"警匪","v":"/class/警匪"},{"n":"冒险","v":"/class/冒险"},{"n":"穿越","v":"/class/穿越"},{"n":"仙侠","v":"/class/仙侠"},{"n":"武侠","v":"/class/武侠"},{"n":"悬疑","v":"/class/悬疑"},{"n":"罪案","v":"/class/罪案"},{"n":"家庭","v":"/class/家庭"},{"n":"历史","v":"/class/历史"},{"n":"年代","v":"/class/年代"},{"n":"农村","v":"/class/农村"},{"n":"其他","v":"/class/其他"}]},{"key":"area","name":"地区","value":[{"n":"全部地区","v":""},{"n":"内地","v":"/area/内地"},{"n":"中国香港","v":"/area/中国香港"},{"n":"中国台湾","v":"/area/中国台湾"},{"n":"美国","v":"/area/美国"},{"n":"日本","v":"/area/日本"},{"n":"韩国","v":"/area/韩国"},{"n":"泰国","v":"/area/泰国"},{"n":"印度","v":"/area/印度"},{"n":"英国","v":"/area/英国"},{"n":"法国","v":"/area/法国"},{"n":"德国","v":"/area/德国"},{"n":"加拿大","v":"/area/加拿大"},{"n":"西班牙","v":"/area/西班牙"},{"n":"意大利","v":"/area/意大利"},{"n":"澳大利亚","v":"/area/澳大利亚"},{"n":"其它","v":"/area/其它"}]},{"key":"year","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2025","v":"/year/2025"},{"n":"2024","v":"/year/2024"},{"n":"2023","v":"/year/2023"},{"n":"2022","v":"/year/2022"},{"n":"2021","v":"/year/2021"},{"n":"2020","v":"/year/2020"},{"n":"2019","v":"/year/2019"},{"n":"2018","v":"/year/2018"},{"n":"2017","v":"/year/2017"},{"n":"2016","v":"/year/2016"},{"n":"2015","v":"/year/2015"},{"n":"2014","v":"/year/2014"},{"n":"2013","v":"/year/2013"},{"n":"2012","v":"/year/2012"},{"n":"2011","v":"/year/2011"},{"n":"2010","v":"/year/2010"},{"n":"2009","v":"/year/2009"},{"n":"2008","v":"/year/2008"},{"n":"2007","v":"/year/2007"},{"n":"2006","v":"/year/2006"},{"n":"2005","v":"/year/2005"},{"n":"2004","v":"/year/2004"}]},{"key":"by","name":"排序","value":[{"n":"时间","v":"/by/time"},{"n":"人气","v":"/by/hits"},{"n":"评分","v":"/by/score"}]}], + "/id/88":[{"key":"class","name":"类型","value":[{"n":"全部类型","v":""},{"n":"偶像","v":"/class/偶像"},{"n":"舞蹈","v":"/class/舞蹈"},{"n":"音乐","v":"/class/音乐"},{"n":"情感","v":"/class/情感"},{"n":"喜剧","v":"/class/喜剧"},{"n":"体育","v":"/class/体育"},{"n":"游戏","v":"/class/游戏"},{"n":"相声","v":"/class/相声"},{"n":"婚恋","v":"/class/婚恋"},{"n":"时尚","v":"/class/时尚"},{"n":"晚会","v":"/class/晚会"},{"n":"明星","v":"/class/明星"},{"n":"访谈","v":"/class/访谈"},{"n":"亲子","v":"/class/亲子"},{"n":"生活","v":"/class/生活"},{"n":"文化","v":"/class/文化"},{"n":"美食","v":"/class/美食"},{"n":"旅游","v":"/class/旅游"},{"n":"益智","v":"/class/益智"},{"n":"其他","v":"/class/其他"}]},{"key":"area","name":"地区","value":[{"n":"全部地区","v":""},{"n":"内地","v":"/area/内地"},{"n":"港台","v":"/area/港台"},{"n":"日韩","v":"/area/日韩"},{"n":"欧美","v":"/area/欧美"}]},{"key":"year","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2025","v":"/year/2025"},{"n":"2024","v":"/year/2024"},{"n":"2023","v":"/year/2023"},{"n":"2022","v":"/year/2022"},{"n":"2021","v":"/year/2021"},{"n":"2020","v":"/year/2020"},{"n":"2019","v":"/year/2019"},{"n":"2018","v":"/year/2018"},{"n":"2017","v":"/year/2017"},{"n":"2016","v":"/year/2016"},{"n":"2015","v":"/year/2015"},{"n":"2014","v":"/year/2014"},{"n":"2013","v":"/year/2013"},{"n":"2012","v":"/year/2012"},{"n":"2011","v":"/year/2011"},{"n":"2010","v":"/year/2010"},{"n":"2009","v":"/year/2009"},{"n":"2008","v":"/year/2008"},{"n":"2007","v":"/year/2007"},{"n":"2006","v":"/year/2006"},{"n":"2005","v":"/year/2005"},{"n":"2004","v":"/year/2004"}]},{"key":"by","name":"排序","value":[{"n":"时间","v":"/by/time"},{"n":"人气","v":"/by/hits"},{"n":"评分","v":"/by/score"}]}], "/id/93":[{"key":"class","name":"类型","value":[{"n":"全部类型","v":""},{"n":"玄幻","v":"/class/玄幻"},{"n":"科幻","v":"/class/科幻"},{"n":"武侠","v":"/class/武侠"},{"n":"冒险","v":"/class/冒险"},{"n":"战斗","v":"/class/战斗"},{"n":"搞笑","v":"/class/搞笑"},{"n":"恋爱","v":"/class/恋爱"},{"n":"魔幻","v":"/class/魔幻"},{"n":"竞技","v":"/class/竞技"},{"n":"悬疑","v":"/class/悬疑"},{"n":"日常","v":"/class/日常"},{"n":"校园","v":"/class/校园"},{"n":"真人","v":"/class/真人"},{"n":"推理","v":"/class/推理"},{"n":"历史","v":"/class/历史"},{"n":"经典","v":"/class/经典"},{"n":"其他","v":"/class/其他"}]},{"key":"area","name":"地区","value":[{"n":"全部地区","v":""},{"n":"国产","v":"/area/国产"},{"n":"日本","v":"/area/日本"},{"n":"欧美","v":"/area/欧美"},{"n":"其他","v":"/area/其他"}]},{"key":"year","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2025","v":"/year/2025"},{"n":"2024","v":"/year/2024"},{"n":"2023","v":"/year/2023"},{"n":"2022","v":"/year/2022"},{"n":"2021","v":"/year/2021"},{"n":"2020","v":"/year/2020"},{"n":"2019","v":"/year/2019"},{"n":"2018","v":"/year/2018"},{"n":"2017","v":"/year/2017"},{"n":"2016","v":"/year/2016"},{"n":"2015","v":"/year/2015"},{"n":"2014","v":"/year/2014"},{"n":"2013","v":"/year/2013"},{"n":"2012","v":"/year/2012"},{"n":"2011","v":"/year/2011"},{"n":"2010","v":"/year/2010"},{"n":"2009","v":"/year/2009"},{"n":"2008","v":"/year/2008"},{"n":"2007","v":"/year/2007"},{"n":"2006","v":"/year/2006"},{"n":"2005","v":"/year/2005"},{"n":"2004","v":"/year/2004"}]},{"key":"by","name":"排序","value":[{"n":"时间","v":"/by/time"},{"n":"人气","v":"/by/hits"},{"n":"评分","v":"/by/score"}]}], + "/id/99":[{"key":"class","name":"类型","value":[{"n":"全部类型","v":""},{"n":"青春","v":"/class/青春"},{"n":"古装","v":"/class/古装"},{"n":"爱情","v":"/class/爱情"},{"n":"都市","v":"/class/都市"},{"n":"喜剧","v":"/class/喜剧"},{"n":"战争","v":"/class/战争"},{"n":"军旅","v":"/class/军旅"},{"n":"谍战","v":"/class/谍战"},{"n":"偶像","v":"/class/偶像"},{"n":"警匪","v":"/class/警匪"},{"n":"冒险","v":"/class/冒险"},{"n":"穿越","v":"/class/穿越"},{"n":"仙侠","v":"/class/仙侠"},{"n":"武侠","v":"/class/武侠"},{"n":"悬疑","v":"/class/悬疑"},{"n":"罪案","v":"/class/罪案"},{"n":"家庭","v":"/class/家庭"},{"n":"历史","v":"/class/历史"},{"n":"年代","v":"/class/年代"},{"n":"农村","v":"/class/农村"},{"n":"其他","v":"/class/其他"}]},{"key":"year","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2025","v":"/year/2025"},{"n":"2024","v":"/year/2024"},{"n":"2023","v":"/year/2023"},{"n":"2022","v":"/year/2022"},{"n":"2021","v":"/year/2021"},{"n":"2020","v":"/year/2020"},{"n":"2019","v":"/year/2019"},{"n":"2018","v":"/year/2018"},{"n":"2017","v":"/year/2017"},{"n":"2016","v":"/year/2016"},{"n":"2015","v":"/year/2015"},{"n":"2014","v":"/year/2014"},{"n":"2013","v":"/year/2013"},{"n":"2012","v":"/year/2012"},{"n":"2011","v":"/year/2011"},{"n":"2010","v":"/year/2010"},{"n":"2009","v":"/year/2009"},{"n":"2008","v":"/year/2008"},{"n":"2007","v":"/year/2007"},{"n":"2006","v":"/year/2006"},{"n":"2005","v":"/year/2005"},{"n":"2004","v":"/year/2004"}]},{"key":"by","name":"排序","value":[{"n":"时间","v":"/by/time"},{"n":"人气","v":"/by/hits"},{"n":"评分","v":"/by/score"}]}], + } +} diff --git "a/js/\347\225\252\350\214\204\345\260\217\350\257\264[\344\271\246].js" "b/js/\347\225\252\350\214\204\345\260\217\350\257\264[\344\271\246].js" index 27b20df..53cb4fe 100644 --- "a/js/\347\225\252\350\214\204\345\260\217\350\257\264[\344\271\246].js" +++ "b/js/\347\225\252\350\214\204\345\260\217\350\257\264[\344\271\246].js" @@ -157,7 +157,7 @@ var rule = { content_url = `https://fanqienovel.com/reader/${input}?enter_from=reader`; log(content_url); let html = (await req(content_url, {headers: {Cookie: getFqCookie()}})).content; - html = html.match(/window.__INITIAL_STATE__=(.+?});/)[1]; + html = html.match(/window.__INITIAL_STATE__=(.+?});/)[1].replaceAll(':undefined,', ':"undefined",'); let json = JSON.parse(html).reader.chapterData; title = json.title; content = decodeText(json.content, 2); diff --git "a/js_dr2/\347\272\242\346\236\234\347\237\255\345\211\247.js" "b/js_dr2/\347\272\242\346\236\234\347\237\255\345\211\247.js" new file mode 100644 index 0000000..73c9b0c --- /dev/null +++ "b/js_dr2/\347\272\242\346\236\234\347\237\255\345\211\247.js" @@ -0,0 +1,28 @@ +var rule = { + title: '红果短剧', + host: 'https://www.hongguodj.cc/', + url: '/show/fyclass--------fypage---.html', + searchUrl: '/search/**----------fypage---.html', + class_parse: '.nav li;a&&Text;a&&href;.*/(.*?).html', + searchable: 2, + quickSearch: 0, + filterable: 0, + headers: { + 'User-Agent': 'MOBILE_UA', + }, + play_parse: true, + lazy: "js:\n let html = request(input);\n let hconf = html.match(/r player_.*?=(.*?))[1];\n let json = JSON5.parse(hconf);\n let url = json.url;\n if (json.encrypt == '1') {\n url = unescape(url);\n } else if (json.encrypt == '2') {\n url = unescape(base64Decode(url));\n }\n if (/\\.(m3u8|mp4|m4a|mp3)/.test(url)) {\n input = {\n parse: 0,\n jx: 0,\n url: url,\n };\n } else {\n input = url && url.startsWith('http') && tellIsJx(url) ? {parse:0,jx:1,url:url}:input;\n }", + limit: 6, + double: true, + 推荐: '.show&&ul;li;img&&alt;img&&data-src;.bg&&Text;a&&href', + 一级: '.list li;img&&alt;img&&data-src;.bg&&Text;a&&href', + 二级: { + title: 'h2&&Text;.info p:eq(2)&&a&&Text', + img: 'img&&src', + desc: '.info p:eq(2)&&a&&Text;.info p:eq(3)&&a&&Text;.info p:eq(4)&&a&&Text;.info p:eq(0)&&a&&Text;.info p:eq(1)&&a&&Text', + content: '#desc&&Text', + tabs: '.play.my-2 .title&&a', + lists: '.play-list:eq(#id)&&.rows li', + }, + 搜索: '.show.rows li;img&&alt;img&&data-src;.bg&&Text;a&&href', +} \ No newline at end of file diff --git a/libs/drpyS.js b/libs/drpyS.js index 97cc42e..fd5b1f8 100644 --- a/libs/drpyS.js +++ b/libs/drpyS.js @@ -342,6 +342,9 @@ export async function getSandbox(env = {}) { setInterval, clearTimeout, clearInterval, + TextEncoder, + TextDecoder, + performance, module: {}, // 模块支持 exports: {}, // 模块支持 rule: {}, // 用于存放导出的 rule 对象 diff --git a/package.json b/package.json index 5f3a151..b38b7fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "drpy-node", - "version": "1.1.22", + "version": "1.1.23", "main": "index.js", "type": "module", "scripts": { diff --git a/public/index.html b/public/index.html index 9023688..b86b6e7 100644 --- a/public/index.html +++ b/public/index.html @@ -8,7 +8,7 @@
nodejs作为服务端的drpy实现。全面升级异步写法积极开发中,每日一更,当前进度 48%
找工作中,随缘更新
nodejs作为服务端的drpy实现。全面升级异步写法积极开发中,每日一更,当前进度 49%
找工作中,随缘更新
更新至V1.1.23
更新至V1.1.22