✨ 阅文集团聚合

https://yuewen.com

情无羁 (8652)11/04 10:48

起点读书webs限免共享

该书源本体来自Yiove仓库,修改正文为服务器缓存内容,不可自行解锁

二维码导入
{
    "bookSourceComment": "",
    "bookSourceGroup": "",
    "bookSourceName": "✨ 阅文集团聚合",
    "bookSourceType": 0,
    "bookSourceUrl": "https:\/\/yuewen.com",
    "customOrder": 200,
    "enabled": true,
    "enabledCookieJar": true,
    "enabledExplore": false,
    "exploreUrl": "",
    "header": "",
    "jsLib": "const encryptKeys = {\n  headers: {\n    QDSign: {\n      key: \"{1dYgqE)h9,R)hKqEcv4]k[h\",\n      iv: \"01234567\"\n    },\n    QDInfo: {\n      key: \"0821CAAD409B84020821CAAD\",\n      iv: String.fromCharCode(0, 0, 0, 0, 0, 0, 0, 0)\n    }\n  }\n}\n\nfunction getDeviceId(java, source) {\n  if (!java || !source) {\n    java = this.java\n    source = this.source\n  }\n  let sVar = JSON.parse(!Packages.android.text.TextUtils.isEmpty(source.getVariable()) ? source.getVariable() : \"{}\")\n  if (!sVar.deviceid) {\n    let temp = \"\"\n    let chr = \"0123456789abcdef\".split(\"\")\n    for (let i = 0; i < 16; i++) { temp = temp + chr[Math.floor(Math.random() * chr.length)]}\n    java.log(temp)\n    sVar.deviceid = temp\n    source.setVariable(JSON.stringify(sVar, null, 2))\n    return temp\n  }\n  return sVar.deviceid\n}\n\nfunction QDSign(path, params, page, dmode) {\n  \/*\n     为保护作者人身氨醛,本函数不包含付费正文的核心请求头检查,只有基础过检测\n    \t 基本够正常使用,如果你有实力可以把其他头(gorgon一类的)自己补全\n  *\/\n  const { java, source } = this\n  let a = params.sort().join(\"&\").replace(\/\\$page\/gi, page)\n  let t = Date.now()\n\n  \/\/ Sign参数\n  let sign = \"Rv1rPTnczce|\" + t + \"||||||\" + java.md5Encode(a.toLowerCase())\n  let Sign = java.tripleDESEncodeBase64Str(sign, encryptKeys.headers.QDSign.key, \"CBC\", \"PKCS5Padding\", encryptKeys.headers.QDSign.iv)\n\n  \/\/ Info参数\n  let id = getDeviceId(java, source)\n  let info = id + \"||||||1||999|\" + t\n  let Info = java.tripleDESEncodeBase64Str(info, encryptKeys.headers.QDInfo.key, \"CBC\", \"PKCS5Padding\", encryptKeys.headers.QDInfo.iv)\n\n  if (dmode) {\n    return {\n      url: \"https:\/\/druidv6.if.qidian.com\/argus\/api\/\" + path + \"?\" + a,\n      headers: {\n        QDSign: Sign,\n        QDInfo: Info,\n        tstamp: String(t)\n      }\n    }\n  }\n  \/\/ Url拼接\n  return \"https:\/\/druidv6.if.qidian.com\/argus\/api\/\" + path + \"?\" + a + \",\" + JSON.stringify({\n    headers: {\n      QDSign: Sign,\n      QDInfo: Info,\n      tstamp: String(t)\n    }\n  })\n}\n\nvar ji = new JavaImporter()\nji.importPackage(Packages.okhttp3)\nwith(ji) {\n  function getBytes(url, headers) {\n    let client = new OkHttpClient()\n\n    let requestBuilder = new Request.Builder()\n      .url(url)\n      .get()\n\n    \/\/ 添加请求头\n    for (let headerName in headers) {\n      requestBuilder.addHeader(headerName, headers[headerName])\n    }\n\n    let request = requestBuilder.build()\n    let response = client.newCall(request).execute()\n\n    try {\n      \/\/ 处理响应\n      let responseBody = response.body().bytes()\n      return responseBody\n    } finally {\n      response.close()\n    }\n  }\n}\n\nfunction dContentQD(cid, body) {\n  const { java, source } = this\n  let aid = getDeviceId(java, source)\n  let sha1 = \"0\" + aid + cid + \"2EEE1433A152E84B3756301D8FA3E69A\"\n  let key0 = java.HMacBase64(sha1, \"HMAC-SHA1\", aid).slice(0, -4)\n  let key1 = java.base64Decode(\"BjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Ng==\")\n  let key2 = java.md5Encode(key1 + key0 + aid)\n  let key3 = java.hexDecodeToByteArray(\"6c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c\" + key2)\n\n  let md5 = Packages.cn.hutool.crypto.digest.DigestUtil.md5(key3)\n  let B = Packages.android.util.Base64\n  let key = B.encodeToString(md5, B.NO_WRAP)\n  let iv = java.base64Decode(\"AAAAAAAAAAA=\")\n\n  return java.createSymmetricCrypto(\"DESede\/CBC\/PKCS5Padding\", key0, iv).decryptStr(java.createSymmetricCrypto(\"DESede\/CBC\/PKCS5Padding\", key, iv).decrypt(Array.from(body).slice(8, -16)))\n}\n\nfunction getLoginHeader() {\n  const { source } = this\n  return JSON.parse(!Packages.android.text.TextUtils.isEmpty(source.getLoginHeader()) ? source.getLoginHeader().slice(0, -1) : \"{}\")\n}\n\nfunction putLoginHeader(data) {\n  const { source } = this\n  source.putLoginHeader(\n    JSON.stringify(data) + \"_\" \/\/ prevent default: 防止阅读将登录头数据加到请求头里\n  )\n}",
    "lastUpdateTime": "1762224496004",
    "loginUi": "[\n{\n  type: \"button\",\n  name: \"                               起点相关                                 \",\n  action: \"empty()\"\n},\n{\n  type: \"button\",\n\tname: \"       [浏览器登录]       \",\n\taction: \"proxyExcWrapper(browserLogin)\"\n},\n{\n  type: \"button\",\n\tname: \"      [凭据登录]       \",\n\taction: \"proxyExcWrapper(tokenLogin)\"\n},\n{\n  type: \"text\",\n  name: \"ywguid\"\n},\n{\n  type: \"password\",\n  name: \"ywkey\"\n}\n]",
    "loginUrl": "<js>\nfunction browserLogin() {\n  try {\n    java.startBrowserAwait(\n      \"https:\/\/qidian.com\", \n      \"登录\"\n    )\n  } catch (e) {}\n  let ywkey = cookie.getKey(\"qidian.com\", \"ywkey\")\n  let ywguid = cookie.getKey(\"qidian.com\", \"ywguid\")\n  putLoginHeader({\n  \t  guid: ywguid,\n  \t  key: ywkey\n  })\n  cookie.removeCookie(\"qidian.com\")\n  \/\/ java.toast(\"没做完:(\")\n}\n\nfunction login() {}\n\nfunction tokenLogin() {\n  if (source.getLoginInfoMap() == null) {\n    java.toast(\"未获取到LoginInfoMap,请尝试重新打开登录UI再按一遍\")\n  }\n  putLoginHeader({\n    guid: source.getLoginInfoMap()[\"ywguid\"],\n    key: source.getLoginInfoMap()[\"ywkey\"]\n  })\n  java.toast(\"凭据保存成功\")\n}\n\nfunction proxyExcWrapper(fun) {\n  try {\n    fun()\n  } catch (e) {\n    java.log(e.toString() + \"\\n\" + e.stack)\n  }\n}\n\nfunction empty() {\n  java.toast(\"别点了,用来看的\")\n}\n<\/js>",
    "respondTime": 1436,
    "ruleBookInfo": {
        "author": "Author",
        "coverUrl": "https:\/\/bookcover.yuewen.com\/qdbimg\/349573\/{{$.BookId}}\/600.webp",
        "init": "<js>\nvar Regs = [\/bookId=(\\d+)\/i, \/\\.com\\D+?\\\/(\\d+)\/i, \/(\\d+)\/i];\nvar bookId = \"\";\nfor (let Reg of Regs) {\n    let mat = baseUrl.match(Reg);\n    if (mat) {\n        bookId = mat[1];\n        break;\n    }\n}\njava.ajax(QDSign(\"v2\/bookdetail\/get\", [\n    \"bookId=\" + bookId\n]))\n<\/js>\n$.Data",
        "intro": "<p>{{$.Description}}",
        "kind": "{{java.getString(\"$..IsInBlackList\")==1?\"非限免\":\"限免\"}}|{{$.BookStatus##完本##完结}}|{{String(java.timeFormat(java.getString(\"LastVipChapterUpdateTime\")==0?java.getString(\"LastChapterUpdateTime\"):java.getString(\"LastVipChapterUpdateTime\"))).replace(\/\\s*\\d+:\\d+\/,\"\")}}\n{{(java.getString(\"$.WordsCnt\")\/10000).toFixed(1)+\"万\"}}\n{{$.CategoryName}}|{{$.SubCategoryName}}\n<js>##(?m)\\|$<\/js>",
        "lastChapter": "{{$.LastVipUpdateChapterName||$.LastUpdateChapterName}}",
        "name": "BookName",
        "tocUrl": "BookId\n<js>java.base64Encode(result)<\/js>\ndata:bookId;base64,{{result}},{\"type\":\"ywc\"}",
        "wordCount": ""
    },
    "ruleContent": {
        "content": "<js>\nlet info = JSON.parse(java.hexDecodeToString(result))\n\nlet content = \"\"\nlet header = getLoginHeader()\n\nswitch (info.source) {\n  case \"qd\":\n    let bid = java.hexDecodeToString(java.ajax(book.tocUrl))\n    let cid = info.cid\n    if (info.isVip) {\n      let url = `https:\/\/static.yesui.me\/api\/content.php?bookId=${bid}&chapterId=${cid}`\n      java.log(url)\n      result=java.ajax(url)\n      java.log(result)\n      content=JSON.parse(result).content\n      \n    } else {\n      let request = QDSign(\"v2\/bookcontent\/safegetcontent\", [\n        \"bookId=\" + bid,\n        \"chapterId=\" + cid\n      ], \"\", true)\n\n      let body = getBytes(request.url, request.headers)\n      let decrypt = dContentQD(cid, body)\n      let raw = JSON.parse(decrypt)\n      let cArr = raw.Content.split(\"\\r\\n\")\n      let blocks = {}\n      for (let i of raw.Blocks) {\n        blocks[i.Sort] = i\n      }\n      for (let i = 0; i < cArr.length; i++) {\n        content += cArr[i] + \"\\n\"\n        if (blocks[i + 1] && blocks[i + 1].Type == \"image\") content += `<img src=\"${blocks[i + 1].Url}\">\\n`\n      }\n    }\n}\n\ncontent\n<\/js>",
        "imageStyle": "FULL",
        "replaceRegex": ""
    },
    "ruleExplore": {
        "author": "",
        "bookList": "",
        "bookUrl": "",
        "coverUrl": "",
        "intro": "",
        "kind": "",
        "name": "",
        "wordCount": ""
    },
    "ruleSearch": {
        "author": "AuthorName||Author",
        "bookList": ".BookCard&&Data.Books&&Data.Data.Items||Data.RankBookList",
        "bookUrl": "https:\/\/druid.if.qidian.com\/argus\/api\/v2\/bookdetail\/get?bookId={{$.BookId}}",
        "checkKeyWord": "",
        "coverUrl": "https:\/\/bookcover.yuewen.com\/qdbimg\/349573\/{{$.BookId}}\/600.webp",
        "intro": "Description||Desc",
        "kind": "{{$.ActionStatusString||$.BookStatus##完本##完结}}\n{{(java.getString(\"$.WordsCount\")\/10000).toFixed(1)+\"万\"}}\n{{$.CategoryName}}|{{$.SubCategoryName}}\n<js>##(?m)\\|$<\/js>",
        "lastChapter": "",
        "name": "BookName",
        "wordCount": ""
    },
    "ruleToc": {
        "chapterList": "@js:\nbookId = java.hexDecodeToString(result);\n$ = JSON.parse(java.ajax(QDSign(\"v1\/chapterlist\/chapterlist\", [\n    \"bookId=\" + bookId\n])))[\"Data\"];\nv_Names = {};\nc_Array = [];\nc_Json = {};\n\n\nfunction b64Url(item_id) {\n    return `data:chapterId;base64,${java.base64Encode(item_id)},{\"type\":\"ywc\"}`;\n}\n\n\nfunction push(vc, a, b, c, d, e, f) {\n    let list = c_Json[vc];\n    if(!list) c_Json[vc] = list = [];\n    \/\/ if (!e==1 || false) return\n    list.push({\n        \"ChapterName\": a || \"\",\n        \"isVolume\": b || false,\n        \"chapterUrl\": c ? b64Url(\n          JSON.stringify({\n            source: \"qd\",\n            cid: c || null,\n            isVip: e==1 || false,\n            isPay: f==1 || false,\n            ccid: null,\n            cbid: null\n          })) : \"\",\n        \"ChapterInfo\": d || \"\",\n        \"isVip\": e==1 || false,\n        \"isPay\": f==1 || false\n    });\n}\n\n\nlet t_List = $.Volumes;\nfor (let $$ of t_List) {\n\t  let Vc = $$.VolumeCode;\n    v_Names[Vc] = $$.VolumeName;\n    c_Json[Vc] = [];\n    if (t_List.length > 1) {\n        push(Vc, $$.VolumeName, true);\n    }\n}\n\n\nt_List = $.Chapters.slice(1);\nfor (let $$ of t_List) {\n    let c_name = v_Names[$$.Vc] || \"未知分卷\";\n    let c_time = java.timeFormatUTC($$.T, 'yyyy-MM-dd HH:mm:ss', 12);\n    let c_word = $$.W + \"字\";\n    let c_info = [c_name, c_time, c_word].join(\"丨\");\n    push($$.Vc, $$.N, false, $$.C, c_info, $$.V, $$.P);\n}\n\n\nfor(let i in c_Json){\nc_Array = c_Array.concat(c_Json[i]);\n}\nc_Array;",
        "chapterName": "ChapterName",
        "chapterUrl": "chapterUrl",
        "isPay": "isPay",
        "isVip": "isVip",
        "isVolume": "isVolume",
        "preUpdateJs": "",
        "updateTime": "ChapterInfo"
    },
    "searchUrl": "@js:\nQDSign(\"v1\/booksearch\/searchbooks\", [\n    \"keyword=\" + java.key,\n    \"pageIndex=\" + page,\n    \"pageSize=20\"\n])",
    "weight": 0
}
广告