From ae3d23a4fbb8a4a78ff82c71d6215a9acffcc176 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 15:51:34 +0800 Subject: [PATCH 01/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 52 +++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index f669f7ff..69cd36f8 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -936,7 +936,7 @@ export class Jjwxc extends BaseRuleClass { "chapterIds" ); chapterGetInfoUrl += - "&versionCode=287&token=" + sid + "¬eislock=1"; + "&versionCode=313&token=" + sid + "¬eislock=1"; } else { throw new Error( `当前需要手动捕获android版app token,详见github主页说明` @@ -948,32 +948,58 @@ export class Jjwxc extends BaseRuleClass { log.debug( `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` ); + if (isVIP){ + bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); + return new Promise((resolve) => { + _GM_xmlhttpRequest({ + url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", + headers: { + accept: "application/json", + referer: "http://android.jjwxc.net?v=313", + not_tip: "updateTime", + "user-agent": + "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", + "accept-encoding": "gzip", + }, + method: "POST", + data: JSON.stringify(bodycontent), + onload: function (response) { + if (response.status === 200) { + retryTime = 0; + const resultI: vipChapterInfo = JSON.parse( + response.responseText + ); + resolve(resultI.downloadContent[0]); + } else { + const resultI: ChapterInfo = JSON.parse( + '{"message":"try again!"}' + ); + resolve(resultI); + } + }, + }); + }); + } + else return new Promise((resolve) => { _GM_xmlhttpRequest({ url: url, headers: { accept: "application/json", - referer: "http://android.jjwxc.net?v=287", + referer: "http://android.jjwxc.net?v=313", not_tip: "updateTime", "user-agent": - "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 287(Pixel3XL; Scale / 3.5)", + "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", "accept-encoding": "gzip", }, method: "GET", onload: function (response) { if (response.status === 200) { retryTime = 0; - if (isVIP) { - const resultI: vipChapterInfo = JSON.parse( - response.responseText - ); - resolve(resultI.downloadContent[0]); - } else { - const resultI: ChapterInfo = JSON.parse( + const resultI: ChapterInfo = JSON.parse( response.responseText - ); - resolve(resultI); - } + ); + resolve(resultI); } else { const resultI: ChapterInfo = JSON.parse( '{"message":"try again!"}' From 8d899b83e1ab5953be988970e83599b7de0e7a36 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 15:54:16 +0800 Subject: [PATCH 02/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 69cd36f8..f91fce4d 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -918,7 +918,7 @@ export class Jjwxc extends BaseRuleClass { ); chapterGetInfoUrl = chapterGetInfoUrl.replace( "http://my.jjwxc.net/onebook_vip.php?", - "https://android.jjwxc.net/androidapi/androidChapterBatchDownload?" + "https://android.jjwxc.net/androidapi/androidChapterBatchDownload" ); //let sid = getCookieObj("token"); if (isVIP) { From 99ac5db0dea2ba16a38e5b70b907577d5c543c97 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:00:42 +0800 Subject: [PATCH 03/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index f91fce4d..9823e353 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -949,7 +949,7 @@ export class Jjwxc extends BaseRuleClass { `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` ); if (isVIP){ - bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); + let bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); return new Promise((resolve) => { _GM_xmlhttpRequest({ url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", From db4bad91cd515d2560d56d2aed43c4695372938d Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:03:30 +0800 Subject: [PATCH 04/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 9823e353..7b49785d 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -949,7 +949,7 @@ export class Jjwxc extends BaseRuleClass { `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` ); if (isVIP){ - let bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); + const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); return new Promise((resolve) => { _GM_xmlhttpRequest({ url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", From 0a86fb00c688de6172806706253cbac61775b5e1 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:24:50 +0800 Subject: [PATCH 05/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 74 +++++++++++++++-------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 7b49785d..c2681668 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -918,7 +918,7 @@ export class Jjwxc extends BaseRuleClass { ); chapterGetInfoUrl = chapterGetInfoUrl.replace( "http://my.jjwxc.net/onebook_vip.php?", - "https://android.jjwxc.net/androidapi/androidChapterBatchDownload" + "https://android.jjwxc.net/androidapi/androidChapterBatchDownload?" ); //let sid = getCookieObj("token"); if (isVIP) { @@ -936,7 +936,7 @@ export class Jjwxc extends BaseRuleClass { "chapterIds" ); chapterGetInfoUrl += - "&versionCode=313&token=" + sid + "¬eislock=1"; + "&versionCode=313&token=" + sid; } else { throw new Error( `当前需要手动捕获android版app token,详见github主页说明` @@ -948,15 +948,14 @@ export class Jjwxc extends BaseRuleClass { log.debug( `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` ); - if (isVIP){ - const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload",""); + if (isVIP) { + const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload?", ""); return new Promise((resolve) => { _GM_xmlhttpRequest({ url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", headers: { accept: "application/json", referer: "http://android.jjwxc.net?v=313", - not_tip: "updateTime", "user-agent": "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", "accept-encoding": "gzip", @@ -964,12 +963,15 @@ export class Jjwxc extends BaseRuleClass { method: "POST", data: JSON.stringify(bodycontent), onload: function (response) { + log.debug( + `取回内容: ${response}, ` + ); if (response.status === 200) { retryTime = 0; - const resultI: vipChapterInfo = JSON.parse( - response.responseText - ); - resolve(resultI.downloadContent[0]); + const resultI: vipChapterInfo = JSON.parse( + response.responseText + ); + resolve(resultI.downloadContent[0]); } else { const resultI: ChapterInfo = JSON.parse( '{"message":"try again!"}' @@ -981,34 +983,36 @@ export class Jjwxc extends BaseRuleClass { }); } else - return new Promise((resolve) => { - _GM_xmlhttpRequest({ - url: url, - headers: { - accept: "application/json", - referer: "http://android.jjwxc.net?v=313", - not_tip: "updateTime", - "user-agent": - "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", - "accept-encoding": "gzip", - }, - method: "GET", - onload: function (response) { - if (response.status === 200) { - retryTime = 0; - const resultI: ChapterInfo = JSON.parse( + { + return new Promise((resolve) => { + _GM_xmlhttpRequest({ + url: url, + headers: { + accept: "application/json", + referer: "http://android.jjwxc.net?v=313", + not_tip: "updateTime", + "user-agent": + "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", + "accept-encoding": "gzip", + }, + method: "GET", + onload: function (response) { + if (response.status === 200) { + retryTime = 0; + const resultI: ChapterInfo = JSON.parse( response.responseText - ); - resolve(resultI); - } else { - const resultI: ChapterInfo = JSON.parse( - '{"message":"try again!"}' - ); - resolve(resultI); - } - }, + ); + resolve(resultI); + } else { + const resultI: ChapterInfo = JSON.parse( + '{"message":"try again!"}' + ); + resolve(resultI); + } + }, + }); }); - }); + } } let result = await getChapterInfo(chapterGetInfoUrl.toString()); while ("message" in result && result.message == "try again!") { From 017d3fc41816f141255ad027b15755e9811963e6 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:31:11 +0800 Subject: [PATCH 06/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index c2681668..3beff197 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -950,6 +950,9 @@ export class Jjwxc extends BaseRuleClass { ); if (isVIP) { const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload?", ""); + log.debug( + `body内容: ${bodycontent}, ` + ); return new Promise((resolve) => { _GM_xmlhttpRequest({ url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", From 71ed8cc8cdb5e37c41d11dd7038e0952ae3f736b Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:39:09 +0800 Subject: [PATCH 07/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 3beff197..d4763b26 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -950,9 +950,6 @@ export class Jjwxc extends BaseRuleClass { ); if (isVIP) { const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload?", ""); - log.debug( - `body内容: ${bodycontent}, ` - ); return new Promise((resolve) => { _GM_xmlhttpRequest({ url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", @@ -964,7 +961,7 @@ export class Jjwxc extends BaseRuleClass { "accept-encoding": "gzip", }, method: "POST", - data: JSON.stringify(bodycontent), + data: bodycontent, onload: function (response) { log.debug( `取回内容: ${response}, ` From 340247c578089471c0f7fcbd46acf9ebdd12b0c4 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 16:49:22 +0800 Subject: [PATCH 08/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index d4763b26..2aacbb73 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -963,9 +963,6 @@ export class Jjwxc extends BaseRuleClass { method: "POST", data: bodycontent, onload: function (response) { - log.debug( - `取回内容: ${response}, ` - ); if (response.status === 200) { retryTime = 0; const resultI: vipChapterInfo = JSON.parse( @@ -982,8 +979,7 @@ export class Jjwxc extends BaseRuleClass { }); }); } - else - { + else{ return new Promise((resolve) => { _GM_xmlhttpRequest({ url: url, From 5c4b83653329c4b5d5aeaa8cf665ca21b5ed054e Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 18:27:42 +0800 Subject: [PATCH 09/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 139 ++++++++++++++++------------ 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 2aacbb73..4a376e61 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -887,6 +887,52 @@ export class Jjwxc extends BaseRuleClass { message: string; //"[本章节已锁定]" } let retryTime = 0; + function decodeVIPResopnce(respose) { + let v43, v38, dest; + const arr = respose.responseHeaders.trim().split(/[\r\n]+/); + const headerMap = {}; + arr.forEach((line) => { + const parts = line.split(": "); + const header = parts.shift(); + const value = parts.join(": "); + headerMap[header] = value; + }); + let accesskey = String(headerMap["accesskey"]); + let keyString = String(headerMap["keystring"]); + let content = String(respose.responseText); + let accesskeyLen = accesskey.length; + let v9 = 0; + let v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(); + for (let i = 0; i < accesskeyLen; i++) { + v9 += accesskey[i].charCodeAt(); + } + let v15 = v9 % keyString.length; + let v17 = parseInt(v9 / 65); + let v18 = keyString.length; + if (v17 + v15 > v18) { + v43 = keyString.substring(v15, (v18 - v16) + v15) + } else { + v43 = keyString.substring(v15, v17 + v15) + } + let v32 = content.length; + if ((v6 & 1) != 0) { + v38 = content.substring(v32 - 12, v32) + dest = content.substring(0, v32 - 12) + } else { + v38 = content.substring(0, 12); + dest = content.substring(12, content.length); + } + let key = CryptoJS.MD5(v43 + v38).toString().substring(0, 8); + let iv = CryptoJS.MD5(v38).toString().substring(0, 8); + const keyHex = CryptoJS.enc.Utf8.parse(key); + const ivHex = CryptoJS.enc.Utf8.parse(iv); + const decrypted = CryptoJS.DES.decrypt(content, keyHex, { + iv: ivHex, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + }); + return decrypted.toString(CryptoJS.enc.Utf8); + } function decodeVIPText(text: string) { const keyHex = CryptoJS.enc.Utf8.parse("KW8Dvm2N"); const ivHex = CryptoJS.enc.Utf8.parse("1ae2c94b"); @@ -897,6 +943,7 @@ export class Jjwxc extends BaseRuleClass { }); return decrypted.toString(CryptoJS.enc.Utf8); } + function getCookieObj(pairKey: string) { const cookieStr = document.cookie; const pairList = cookieStr.split(";"); @@ -918,7 +965,7 @@ export class Jjwxc extends BaseRuleClass { ); chapterGetInfoUrl = chapterGetInfoUrl.replace( "http://my.jjwxc.net/onebook_vip.php?", - "https://android.jjwxc.net/androidapi/androidChapterBatchDownload?" + "https://android.jjwxc.net/androidapi/chapterContent?" ); //let sid = getCookieObj("token"); if (isVIP) { @@ -931,12 +978,12 @@ export class Jjwxc extends BaseRuleClass { if (typeof (unsafeWindow as UnsafeWindow).tokenOptions === "object") { const sid = (unsafeWindow as UnsafeWindow).tokenOptions?.Jjwxc; //sid = self.atob(decodeURIComponent(sid)).replace(/\|\|.*/, '').replace(/\|/, '_').replace(/\|.*/, ''); - chapterGetInfoUrl = chapterGetInfoUrl.replace( - "chapterId", - "chapterIds" - ); + // chapterGetInfoUrl = chapterGetInfoUrl.replace( + // "chapterId", + // "chapterIds" + // ); chapterGetInfoUrl += - "&versionCode=313&token=" + sid; + "&versionCode=287&token=" + sid + "¬eislock=1"; } else { throw new Error( `当前需要手动捕获android版app token,详见github主页说明` @@ -944,71 +991,47 @@ export class Jjwxc extends BaseRuleClass { } //} } + async function getChapterInfo(url: string): Promise { log.debug( `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` ); - if (isVIP) { - const bodycontent = url.replace("https://android.jjwxc.net/androidapi/androidChapterBatchDownload?", ""); - return new Promise((resolve) => { - _GM_xmlhttpRequest({ - url: "https://android.jjwxc.net/androidapi/androidChapterBatchDownload", - headers: { - accept: "application/json", - referer: "http://android.jjwxc.net?v=313", - "user-agent": - "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", - "accept-encoding": "gzip", - }, - method: "POST", - data: bodycontent, - onload: function (response) { - if (response.status === 200) { - retryTime = 0; + return new Promise((resolve) => { + _GM_xmlhttpRequest({ + url: url, + headers: { + accept: "application/json", + referer: "http://android.jjwxc.net?v=287", + not_tip: "updateTime", + "user-agent": + "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 287(Pixel3XL; Scale / 3.5)", + "accept-encoding": "gzip", + }, + method: "GET", + onload: function (response) { + if (response.status === 200) { + retryTime = 0; + if (isVIP) { + const decodeResponseText = decodeVIPResopnce(response); const resultI: vipChapterInfo = JSON.parse( - response.responseText - ); - resolve(resultI.downloadContent[0]); - } else { - const resultI: ChapterInfo = JSON.parse( - '{"message":"try again!"}' - ); - resolve(resultI); - } - }, - }); - }); - } - else{ - return new Promise((resolve) => { - _GM_xmlhttpRequest({ - url: url, - headers: { - accept: "application/json", - referer: "http://android.jjwxc.net?v=313", - not_tip: "updateTime", - "user-agent": - "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 313(Pixel3XL; Scale / 3.5)", - "accept-encoding": "gzip", - }, - method: "GET", - onload: function (response) { - if (response.status === 200) { - retryTime = 0; - const resultI: ChapterInfo = JSON.parse( - response.responseText + decodeResponseText ); resolve(resultI); } else { const resultI: ChapterInfo = JSON.parse( - '{"message":"try again!"}' + response.responseText ); resolve(resultI); } - }, - }); + } else { + const resultI: ChapterInfo = JSON.parse( + '{"message":"try again!"}' + ); + resolve(resultI); + } + }, }); - } + }); } let result = await getChapterInfo(chapterGetInfoUrl.toString()); while ("message" in result && result.message == "try again!") { From 7c5d563bdd83e5a4b37362480805d81191c284d9 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 18:30:36 +0800 Subject: [PATCH 10/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 4a376e61..f77a2795 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -897,24 +897,24 @@ export class Jjwxc extends BaseRuleClass { const value = parts.join(": "); headerMap[header] = value; }); - let accesskey = String(headerMap["accesskey"]); - let keyString = String(headerMap["keystring"]); - let content = String(respose.responseText); - let accesskeyLen = accesskey.length; + const accesskey = String(headerMap["accesskey"]); + const keyString = String(headerMap["keystring"]); + const content = String(respose.responseText); + const accesskeyLen = accesskey.length; let v9 = 0; - let v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(); + const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(); for (let i = 0; i < accesskeyLen; i++) { v9 += accesskey[i].charCodeAt(); } - let v15 = v9 % keyString.length; - let v17 = parseInt(v9 / 65); - let v18 = keyString.length; + const v15 = v9 % keyString.length; + const v17 = parseInt(v9 / 65); + const v18 = keyString.length; if (v17 + v15 > v18) { v43 = keyString.substring(v15, (v18 - v16) + v15) } else { v43 = keyString.substring(v15, v17 + v15) } - let v32 = content.length; + const v32 = content.length; if ((v6 & 1) != 0) { v38 = content.substring(v32 - 12, v32) dest = content.substring(0, v32 - 12) @@ -922,8 +922,8 @@ export class Jjwxc extends BaseRuleClass { v38 = content.substring(0, 12); dest = content.substring(12, content.length); } - let key = CryptoJS.MD5(v43 + v38).toString().substring(0, 8); - let iv = CryptoJS.MD5(v38).toString().substring(0, 8); + const key = CryptoJS.MD5(v43 + v38).toString().substring(0, 8); + const iv = CryptoJS.MD5(v38).toString().substring(0, 8); const keyHex = CryptoJS.enc.Utf8.parse(key); const ivHex = CryptoJS.enc.Utf8.parse(iv); const decrypted = CryptoJS.DES.decrypt(content, keyHex, { From a159cc632934da0b46ef2a4bf5b2c3669ee58edf Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 18:40:02 +0800 Subject: [PATCH 11/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index f77a2795..97104589 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -887,19 +887,19 @@ export class Jjwxc extends BaseRuleClass { message: string; //"[本章节已锁定]" } let retryTime = 0; - function decodeVIPResopnce(respose) { + function decodeVIPResopnce(responseHeader: String, responseText:String) { let v43, v38, dest; - const arr = respose.responseHeaders.trim().split(/[\r\n]+/); + const arr = responseHeader.trim().split(/[\r\n]+/); const headerMap = {}; arr.forEach((line) => { const parts = line.split(": "); - const header = parts.shift(); + const header = String(parts.shift()); const value = parts.join(": "); headerMap[header] = value; }); const accesskey = String(headerMap["accesskey"]); const keyString = String(headerMap["keystring"]); - const content = String(respose.responseText); + const content = String(responseText); const accesskeyLen = accesskey.length; let v9 = 0; const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(); @@ -1012,7 +1012,7 @@ export class Jjwxc extends BaseRuleClass { if (response.status === 200) { retryTime = 0; if (isVIP) { - const decodeResponseText = decodeVIPResopnce(response); + const decodeResponseText = decodeVIPResopnce(response.responseHeaders, String(response.responseText)); const resultI: vipChapterInfo = JSON.parse( decodeResponseText ); From e23289a6174b59baf303ee34fc9c06e9a9370b9a Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 18:41:46 +0800 Subject: [PATCH 12/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 97104589..59fbbd40 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -887,7 +887,7 @@ export class Jjwxc extends BaseRuleClass { message: string; //"[本章节已锁定]" } let retryTime = 0; - function decodeVIPResopnce(responseHeader: String, responseText:String) { + function decodeVIPResopnce(responseHeader: string, responseText:string) { let v43, v38, dest; const arr = responseHeader.trim().split(/[\r\n]+/); const headerMap = {}; From 82cccbde4adb6236da41b23f8ab968e53d6aa92f Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 19:06:21 +0800 Subject: [PATCH 13/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 59fbbd40..f56f4ebc 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -890,27 +890,27 @@ export class Jjwxc extends BaseRuleClass { function decodeVIPResopnce(responseHeader: string, responseText:string) { let v43, v38, dest; const arr = responseHeader.trim().split(/[\r\n]+/); - const headerMap = {}; + const headerMap= { }; arr.forEach((line) => { const parts = line.split(": "); - const header = String(parts.shift()); + const header = parts.shift(); const value = parts.join(": "); - headerMap[header] = value; + headerMap[header as string] = value; }); const accesskey = String(headerMap["accesskey"]); const keyString = String(headerMap["keystring"]); const content = String(responseText); const accesskeyLen = accesskey.length; let v9 = 0; - const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(); + const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(0); for (let i = 0; i < accesskeyLen; i++) { - v9 += accesskey[i].charCodeAt(); + v9 += accesskey[i].charCodeAt(0); } const v15 = v9 % keyString.length; - const v17 = parseInt(v9 / 65); + const v17 = v9 / 65; const v18 = keyString.length; if (v17 + v15 > v18) { - v43 = keyString.substring(v15, (v18 - v16) + v15) + v43 = keyString.substring(v15, (v18 - v17) + v15) } else { v43 = keyString.substring(v15, v17 + v15) } @@ -1013,7 +1013,7 @@ export class Jjwxc extends BaseRuleClass { retryTime = 0; if (isVIP) { const decodeResponseText = decodeVIPResopnce(response.responseHeaders, String(response.responseText)); - const resultI: vipChapterInfo = JSON.parse( + const resultI: ChapterInfo = JSON.parse( decodeResponseText ); resolve(resultI); From 4bd28ea24f0a5b019306cb8b3d814aaf22786732 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 19:12:41 +0800 Subject: [PATCH 14/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index f56f4ebc..7da492ad 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -890,7 +890,7 @@ export class Jjwxc extends BaseRuleClass { function decodeVIPResopnce(responseHeader: string, responseText:string) { let v43, v38, dest; const arr = responseHeader.trim().split(/[\r\n]+/); - const headerMap= { }; + const headerMap = { "accesskey": "0", "keystring" :"0"}; arr.forEach((line) => { const parts = line.split(": "); const header = parts.shift(); From 1a32d901a0f892fafe3148bda814accbcc873d0d Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 19:20:36 +0800 Subject: [PATCH 15/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 7da492ad..0c70ce01 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -895,7 +895,7 @@ export class Jjwxc extends BaseRuleClass { const parts = line.split(": "); const header = parts.shift(); const value = parts.join(": "); - headerMap[header as string] = value; + headerMap[header as keyof typeof String] = value; }); const accesskey = String(headerMap["accesskey"]); const keyString = String(headerMap["keystring"]); From fbaf34d73becd84ed86064d79562f26043f48670 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 19:28:24 +0800 Subject: [PATCH 16/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 0c70ce01..f6633fac 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -889,16 +889,18 @@ export class Jjwxc extends BaseRuleClass { let retryTime = 0; function decodeVIPResopnce(responseHeader: string, responseText:string) { let v43, v38, dest; + let accesskey = "accesskey", keyString = "keystring"; const arr = responseHeader.trim().split(/[\r\n]+/); const headerMap = { "accesskey": "0", "keystring" :"0"}; arr.forEach((line) => { const parts = line.split(": "); const header = parts.shift(); const value = parts.join(": "); - headerMap[header as keyof typeof String] = value; + if (header == "accesskey") + accesskey = value; + else if (header == "keystring") + keyString = value; }); - const accesskey = String(headerMap["accesskey"]); - const keyString = String(headerMap["keystring"]); const content = String(responseText); const accesskeyLen = accesskey.length; let v9 = 0; From 4b319af40cb0af9fe8639d9f900155b8f09f6f79 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Tue, 20 Feb 2024 19:52:42 +0800 Subject: [PATCH 17/21] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E4=B8=AD=E5=8F=AF=E8=83=BD=E6=9C=89=E7=9A=84?= =?UTF-8?q?=E6=8D=A2=E8=A1=8C=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/special/original/jjwxc.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index f6633fac..54082175 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -901,7 +901,8 @@ export class Jjwxc extends BaseRuleClass { else if (header == "keystring") keyString = value; }); - const content = String(responseText); + let content = String(responseText); + content = (content + '').replace(/\n*$/g, '').replace(/\n/g, ''); const accesskeyLen = accesskey.length; let v9 = 0; const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(0); @@ -1050,6 +1051,7 @@ export class Jjwxc extends BaseRuleClass { let content = result.content; if (isVIP) content = decodeVIPText(content); let postscript = result.sayBody; + if (isVIP) postscript if (result.sayBody == null) postscript = " "; const contentRaw = document.createElement("pre"); contentRaw.innerHTML = content; From 66646222ad6c78187aa878542eb0b5e360257dd2 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Wed, 21 Feb 2024 10:04:00 +0800 Subject: [PATCH 18/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/special/original/jjwxc.ts | 77 ++++++++++++++++------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 54082175..4b2ee82f 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -578,8 +578,8 @@ export class Jjwxc extends BaseRuleClass { char3 = str.charCodeAt(i++); out += String.fromCharCode( ((c & 0x0f) << 12) | - ((char2 & 0x3f) << 6) | - ((char3 & 0x3f) << 0) + ((char2 & 0x3f) << 6) | + ((char3 & 0x3f) << 0) ); break; } @@ -599,9 +599,9 @@ export class Jjwxc extends BaseRuleClass { const data: Record = {}; Array.from(children).forEach( (item) => - (data[item.getAttribute("name") as string] = item.getAttribute( - "value" - ) as string) + (data[item.getAttribute("name") as string] = item.getAttribute( + "value" + ) as string) ); const novelid = parseInt(data["novelid"]); @@ -655,7 +655,7 @@ export class Jjwxc extends BaseRuleClass { if (new Date()["getTime"]() / 1000 - obj["time"] > 86400) { throw new Error( "章节内容解码失败,内容生成时间与当前设备时间相差过大,请刷新页面或校准当前设备时间。内容生成时间为:" + - new Date(obj["time"] * 100).toLocaleString() + new Date(obj["time"] * 100).toLocaleString() ); } }; @@ -710,8 +710,8 @@ export class Jjwxc extends BaseRuleClass { sc.type, ( sc as - | csstree.ClassSelector - | csstree.PseudoElementSelector + | csstree.ClassSelector + | csstree.PseudoElementSelector ).name, ]) ); @@ -758,8 +758,8 @@ export class Jjwxc extends BaseRuleClass { sc.type, ( sc as - | csstree.ClassSelector - | csstree.PseudoElementSelector + | csstree.ClassSelector + | csstree.PseudoElementSelector ).name, ]) ); @@ -887,11 +887,11 @@ export class Jjwxc extends BaseRuleClass { message: string; //"[本章节已锁定]" } let retryTime = 0; - function decodeVIPResopnce(responseHeader: string, responseText:string) { + function decodeVIPResopnce(responseHeader: string, responseText: string) { let v43, v38, dest; let accesskey = "accesskey", keyString = "keystring"; const arr = responseHeader.trim().split(/[\r\n]+/); - const headerMap = { "accesskey": "0", "keystring" :"0"}; + const headerMap = { "accesskey": "0", "keystring": "0" }; arr.forEach((line) => { const parts = line.split(": "); const header = parts.shift(); @@ -902,7 +902,6 @@ export class Jjwxc extends BaseRuleClass { keyString = value; }); let content = String(responseText); - content = (content + '').replace(/\n*$/g, '').replace(/\n/g, ''); const accesskeyLen = accesskey.length; let v9 = 0; const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(0); @@ -913,7 +912,7 @@ export class Jjwxc extends BaseRuleClass { const v17 = v9 / 65; const v18 = keyString.length; if (v17 + v15 > v18) { - v43 = keyString.substring(v15, (v18 - v17) + v15) + v43 = keyString.substring(v15, (v18 - v15) + v15) } else { v43 = keyString.substring(v15, v17 + v15) } @@ -929,12 +928,19 @@ export class Jjwxc extends BaseRuleClass { const iv = CryptoJS.MD5(v38).toString().substring(0, 8); const keyHex = CryptoJS.enc.Utf8.parse(key); const ivHex = CryptoJS.enc.Utf8.parse(iv); - const decrypted = CryptoJS.DES.decrypt(content, keyHex, { - iv: ivHex, - mode: CryptoJS.mode.CBC, - padding: CryptoJS.pad.Pkcs7, - }); - return decrypted.toString(CryptoJS.enc.Utf8); + let result = '{"message":"try again!"}'; + try { + const decrypted = CryptoJS.DES.decrypt(dest, keyHex, { + iv: ivHex, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + }); + result = decrypted.toString(CryptoJS.enc.Utf8); + } catch (e) { + // log.debug(`请求content:${content}`); + result = '{"message":"try again!"}'; + } + return result; } function decodeVIPText(text: string) { const keyHex = CryptoJS.enc.Utf8.parse("KW8Dvm2N"); @@ -968,7 +974,7 @@ export class Jjwxc extends BaseRuleClass { ); chapterGetInfoUrl = chapterGetInfoUrl.replace( "http://my.jjwxc.net/onebook_vip.php?", - "https://android.jjwxc.net/androidapi/chapterContent?" + "https://app.jjwxc.net/androidapi/chapterContent?" ); //let sid = getCookieObj("token"); if (isVIP) { @@ -986,7 +992,7 @@ export class Jjwxc extends BaseRuleClass { // "chapterIds" // ); chapterGetInfoUrl += - "&versionCode=287&token=" + sid + "¬eislock=1"; + "&versionCode=349&token=" + sid ; } else { throw new Error( `当前需要手动捕获android版app token,详见github主页说明` @@ -994,7 +1000,7 @@ export class Jjwxc extends BaseRuleClass { } //} } - + async function getChapterInfo(url: string): Promise { log.debug( `请求地址: ${url}, Referrer: ${chapterUrl}, 重试次数: ${retryTime}` @@ -1003,12 +1009,11 @@ export class Jjwxc extends BaseRuleClass { _GM_xmlhttpRequest({ url: url, headers: { - accept: "application/json", - referer: "http://android.jjwxc.net?v=287", - not_tip: "updateTime", - "user-agent": - "Mozilla/ 5.0(Linux; Android 12; Pixel 3 XL Build / SP1A.210812.016.C1; wv) AppleWebKit / 537.36(KHTML, like Gecko) Version / 4.0 Chrome / 108.0.5359.128 Mobile Safari / 537.36 / JINJIANG - Android / 287(Pixel3XL; Scale / 3.5)", - "accept-encoding": "gzip", + // accept: "application/json", + referer: "http://android.jjwxc.net?v=349", + // not_tip: "updateTime", + "user-agent": "Dalvik/2.1.0", + // "accept-encoding": "gzip", }, method: "GET", onload: function (response) { @@ -1016,9 +1021,13 @@ export class Jjwxc extends BaseRuleClass { retryTime = 0; if (isVIP) { const decodeResponseText = decodeVIPResopnce(response.responseHeaders, String(response.responseText)); - const resultI: ChapterInfo = JSON.parse( - decodeResponseText - ); + let resultI = JSON.parse('{"message":"try again!"}'); + try { + resultI = JSON.parse(decodeResponseText); + } catch (e) { + log.debug(`json:${decodeResponseText}`); + resultI = JSON.parse('{"message":"try again!"}'); + } resolve(resultI); } else { const resultI: ChapterInfo = JSON.parse( @@ -1041,8 +1050,8 @@ export class Jjwxc extends BaseRuleClass { retryTime++; if (retryTime > retryLimit) { retryTime = 0; - log.error(`请求 (不可见url) 失败`); - throw new Error(`请求 (不可见url) 失败`); + log.error(`请求${chapterGetInfoUrl.toString() }$失败`); + throw new Error(`请求${chapterGetInfoUrl.toString() }$失败`); } result = await getChapterInfo(chapterGetInfoUrl.toString()); } From 9fd8bf33fb6fe6bd67bf9293adc9e1d2c8de5586 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Wed, 21 Feb 2024 10:08:28 +0800 Subject: [PATCH 19/21] Update jjwxc.ts --- src/rules/special/original/jjwxc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index 4b2ee82f..cb3829cf 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -901,7 +901,7 @@ export class Jjwxc extends BaseRuleClass { else if (header == "keystring") keyString = value; }); - let content = String(responseText); + const content = String(responseText); const accesskeyLen = accesskey.length; let v9 = 0; const v6 = String(accesskey[accesskeyLen - 1]).charCodeAt(0); From f5b143d2ba9a2b2097eb01b80c924c62429ea81c Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Wed, 21 Feb 2024 19:20:34 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E8=A7=A3=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/special/original/jjwxc.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/rules/special/original/jjwxc.ts b/src/rules/special/original/jjwxc.ts index cb3829cf..1653cd42 100644 --- a/src/rules/special/original/jjwxc.ts +++ b/src/rules/special/original/jjwxc.ts @@ -992,7 +992,7 @@ export class Jjwxc extends BaseRuleClass { // "chapterIds" // ); chapterGetInfoUrl += - "&versionCode=349&token=" + sid ; + "&versionCode=349&token=" + sid; } else { throw new Error( `当前需要手动捕获android版app token,详见github主页说明` @@ -1009,19 +1009,24 @@ export class Jjwxc extends BaseRuleClass { _GM_xmlhttpRequest({ url: url, headers: { - // accept: "application/json", + // accept: "application/json", referer: "http://android.jjwxc.net?v=349", - // not_tip: "updateTime", + // not_tip: "updateTime", "user-agent": "Dalvik/2.1.0", - // "accept-encoding": "gzip", + // "accept-encoding": "gzip", }, method: "GET", onload: function (response) { if (response.status === 200) { retryTime = 0; if (isVIP) { - const decodeResponseText = decodeVIPResopnce(response.responseHeaders, String(response.responseText)); + let decodeResponseText = String(response.responseText); let resultI = JSON.parse('{"message":"try again!"}'); + try { + resultI = JSON.parse(decodeResponseText); + } catch (e) { + decodeResponseText = decodeVIPResopnce(response.responseHeaders, String(response.responseText)); + } try { resultI = JSON.parse(decodeResponseText); } catch (e) { @@ -1050,8 +1055,8 @@ export class Jjwxc extends BaseRuleClass { retryTime++; if (retryTime > retryLimit) { retryTime = 0; - log.error(`请求${chapterGetInfoUrl.toString() }$失败`); - throw new Error(`请求${chapterGetInfoUrl.toString() }$失败`); + log.error(`请求${chapterGetInfoUrl.toString()}$失败`); + throw new Error(`请求${chapterGetInfoUrl.toString()}$失败`); } result = await getChapterInfo(chapterGetInfoUrl.toString()); } From e959114dfa473dbcd56d5c82f0a69732b067fb60 Mon Sep 17 00:00:00 2001 From: Dongmin Li Date: Wed, 21 Feb 2024 23:19:45 +0800 Subject: [PATCH 21/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCP=E4=BD=9C=E8=AF=9D?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E4=B8=BAnull=E8=80=8C=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/special/original/gongzicp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/special/original/gongzicp.ts b/src/rules/special/original/gongzicp.ts index d585f99c..c7954818 100644 --- a/src/rules/special/original/gongzicp.ts +++ b/src/rules/special/original/gongzicp.ts @@ -613,7 +613,7 @@ export class Gongzicp extends BaseRuleClass { }) .join("\n"); - if (chapterInfo.postscript.length === 0) { + if (chapterInfo.postscript === null || chapterInfo.postscript.length === 0) { contentHTML = _contentHTML; } else { contentHTML = document.createElement("div");