[{"enabled":true,"enabledCookieJar":false,"enabledExplore":true,"customButton":false,"eventListener":false,"bookSourceType":0,"bookSourceUrl":"https:\/\/www.mowan.lol","bookSourceName":"魔丸小说","bookSourceGroup":"","bookSourceComment":"番茄小说，七猫小说，塔读小说，书旗小说，起点小说，所有来源均支持段评，本章说\n\ntg群:https:\/\/t.me\/mowanxiaoshuo\n\n魔丸小说转为公益书源，免费为大家提供服务，会员有所特权但不多，会员费用将用于运营维护费，费用透明，可前往用户中心打赏排行榜查看，并可查看阅读榜，如果阅读异常，如每天看几万章这种，会进行封禁处理\n\n书源直链：https:\/\/www.mowan.lol\/api\/book-sources\/yuedu\/download\n注册地址：https:\/\/www.mowan.lol\/user\/register?invite_code=ZGWVOFHD","loginUrl":"https:\/\/www.mowan.lol\/user\/me?app=yuedu&version=26.9.22","loginUi":"","loginCheckJs":"","coverDecodeJs":"","bookUrlPattern":"","header":"","variableComment":"","concurrentRate":"","jsLib":"let mw=\"https:\/\/www.mowan.lol\";function getCookie(k){let{java,cookie}=this;let cookieValue=String(cookie.getCookie(mw))||String(java.getCookie(mw));let parts=cookieValue.split(\";\");for(let i=0;i<parts.length;i++){let part=parts[i].trim();let idx=part.indexOf(k+\"=\");if(idx===0){return part.substring(k.length+1)}}return\"\"}function Api(url,method){method=method||'GET';let{java}=this;let XDeviceID=this.getCookie('X-Device-ID');let Authorization=this.getCookie('Authorization');if(typeof Authorization==='string'){Authorization=Authorization.replace(\"%20\",\" \")}else{Authorization=String(Authorization).replace(\"%20\",\" \")};let options={method:method,headers:JSON.stringify({'Authorization':Authorization,'X-Device-ID':XDeviceID,'Content-Type':'application\/json','User-Agent':'yuedu_app','Referer':mw})};return mw+url+','+JSON.stringify(options)}function showPara(url){let{java,cache}=this;let date=new Date().toLocaleDateString();let cacheKey=date+\"dp\";let htmlContent=cache.get(cacheKey);if(!htmlContent||String(htmlContent).indexOf(\"id=\")===-1){htmlContent=java.ajax(url);cache.put(cacheKey,htmlContent)}let browserConfig={\"expandedCornersRadius\":20,\"dismissOnTouchOutside\":true,\"isDraggable\":true,\"shouldDimBackground\":true,\"backgroundDimAmount\":0.5,\"hardwareAccelerated\":true,\"isNestedScrollingEnabled\":true,\"isGestureInsetBottomIgnored\":true,\"setFitToContents\":true,\"isHideable\":true,\"heightPercentage\":0.8};java.showBrowser(url,htmlContent,\"window.java=java;\",JSON.stringify(browserConfig))}function createBubble(number,url,bubble){let num=number>99?\"99+\":number.toString();bubble=bubble.replace('$num',num);var encodedBubble=this.java.base64Encode(bubble);encodedBubble=`data:image\/svg+xml;base64,${encodedBubble},{\"click\":\"showPara('${mw+url}' )\",\"style\":\"text\"}`;return`<img src=\"${encodedBubble}\">`}function showChapter(url){let{java,cache}=this;let date=new Date().toLocaleDateString();let cacheKey=date+\"end\";let htmlContent=cache.get(cacheKey);if(!htmlContent||String(htmlContent).indexOf(\"id=\")===-1){htmlContent=java.ajax(url);cache.put(cacheKey,htmlContent)}let browserConfig={\"expandedCornersRadius\":20,\"dismissOnTouchOutside\":true,\"isDraggable\":true,\"shouldDimBackground\":true,\"backgroundDimAmount\":0.5,\"hardwareAccelerated\":true,\"isNestedScrollingEnabled\":true,\"isGestureInsetBottomIgnored\":true,\"setFitToContents\":true,\"isHideable\":true,\"heightPercentage\":0.8};java.showBrowser(url,htmlContent,\"window.java=java;\",JSON.stringify(browserConfig))}function createChapter(url,svg){var encodedSvg=this.java.base64Encode(svg);encodedSvg=`data:image\/svg+xml;base64,${encodedSvg},{\"click\":\"showChapter('${mw+url}' )\",\"style\":\"FULL\"}`;return`<img src=\"${encodedSvg}\">`}\n\n\nfunction show(k, v) {\n    const { java, cache } = this;\n    cache.put(v,k)\n    java.refreshExplore();\n}\n\n\nfunction create(k, chars, defaultV, v, size) {\n    return {\n        title: k,\n        type: \"select\",\n        chars: chars,\n        default: defaultV,\n        action: `show(infoMap['${k}'],'${v}')`,\n        style: {\n            layout_flexGrow: 1,\n            layout_flexBasisPercent: size\n        }\n    };\n}\n\nfunction formatDate(input, fmt = 'YYYY-MM-DD HH:mm:ss') {\n  const date = input instanceof Date ? input : new Date(input);\n  if (isNaN(date.getTime())) return '';\n\n  const pad = n => String(n).padStart(2, '0');\n\n  const map = {\n    YYYY: date.getFullYear(),\n    MM: pad(date.getMonth() + 1),\n    DD: pad(date.getDate()),\n    HH: pad(date.getHours()),\n    mm: pad(date.getMinutes()),\n    ss: pad(date.getSeconds())\n  };\n\n  return fmt.replace(\/YYYY|MM|DD|HH|mm|ss\/g, m => map[m]);\n}\n\n\nfunction Env() {\n    const { java, source } = this;\n    try {\n        java.qread();\n        return 4;\n    } catch (e) {}\n    try {\n        if (typeof java.reLoginView === 'function') return 1;\n        new Packages.io.legato.kazusa.utils.TimeoutCancellationException('');\n        return 1;\n    } catch (e) {}\n    try {\n        java.deviceID();\n        return 3;\n    } catch (e) {}\n    if (typeof source.loginUi === 'function') return 2;\n    return 1;\n}\n\nfunction Content(res) {\n\tlet evn = this.Env();\n\tlet content = \"\";\n\tlet text = res.data.paragraphs;\n    if (!text) {\n        return res.data.msg || \"暂无数据，请稍后再试~\";\n    }\n  let enabledPara = res.data.comment.enabled;\n  let bubble = enabledPara ? res.data.comment.bubble.svg : \"\";\n  let enabledChapter = res.data.comment.chapter_enabled;\n  let chapterSvgs = enabledChapter ? res.data.comment.chapter_card.svg : \"\";\n \n  var contents = [];\n  for (var i = 0; i < text.length; i++) {\n    var item = text[i];\n    var html = \"\";\n    if (item.comment_count > 0 && enabledPara && bubble != '' && evn == 1) {\n      html = '<p>' + item.text + this.createBubble(item.comment_count, item.comment_url, bubble) + '<\/p>';\n    } else if (item.comment_count > 0 && enabledPara && bubble != '' && evn == 3) {\n    \thtml = `<div rs-native>${item.text}<comment count=\"${item.comment_count}\" onPress=\"java.showReadingBrowser('${mw+item.comment_url}','段评')\"><\/div>`;\n    \t} else {\n      html = item.text;\n    }\n    if (item.image) {\n      if (typeof item.image === 'string') {\n        html += '<img src=\"' + item.image + '\">';\n      } else if (Array.isArray(item.image)) {\n        for (var j = 0; j < item.image.length; j++) {\n          html += '<img src=\"' + item.image[j] + '\">';\n        }\n      }\n    }\n\n    contents.push(html);\n  }\n\n  content = contents.join(\"\\n\");\n  \n  if (enabledChapter&&chapterSvgs!=\"\" && evn == 1) {\n  \t    let chapterUrl = res.data.comment.chapter_card.url\n  \t   content += '\\n'+ this.createChapter(chapterUrl,chapterSvgs)\n  \t} else if (enabledChapter&&chapterSvgs!=\"\" && evn == 3) {\n  \t    let chapterUrl = res.data.comment.chapter_card.url\n  \t    let enChapterSvgs = java.base64Encode(chapterSvgs);\n  \t   content += `<div rs-native><img onPress=\"java.showReadingBrowser('${mw+chapterUrl}','本章说')\" src=\"data:image\/svg+xml;base64,${enChapterSvgs}\"><\/div>`;\n  \t}\n  \n\treturn content;\n\t}","searchUrl":"<js>Api('\/api\/search?keyword={{key}}&page={{page}}&page_size=20')<\/js>","ruleSearch":{"checkKeyWord":"我的","bookList":"<js>\n\/\/java.log(result)\nresult = JSON.parse(result);\nif (result.code!=0) {\n    result = {\"data\":{\"items\":[\n            {\n                \"name\": \"❗❗❗当前未登录状态\",\n                \"author\": \"请登录后使用\",\n                \"latestChapterTitle\":\"请注册账号并登陆\",\n                \"cover\": \"http:\/\/fc3tn.baidu.com\/it\/u=1573211303,3438572022&fm=203&src=787&fc_m=cvican\",\n                \"description\":result.message,\n                \"id\":\"\",\n                \"source\":\"\"\n            }\n        ]}}\n}\nJSON.stringify(result)\n<\/js>\n$.data.items","name":"name","author":"author","kind":"{{$.category}},{{$.status}}","wordCount":"","lastChapter":"源站：{{$.source}}","intro":"description","coverUrl":"cover","bookUrl":"\/api\/book\/detail?source={{$.source}}&book_id={{$.id}}\n<js>\n`data:;base64,${java.base64Encode(result)},{\"type\":\"mw\"}`\n<\/js>","updateTime":""},"exploreUrl":"<js>\nfunction styles(so) {\n    var today = new Date();\n    var dateT = today.getFullYear()\n        + '-'\n        + (today.getMonth() + 1)\n        + '-'\n        + today.getDate()\n        + '_discover_tabs';\n\n    var url = Api('\/api\/discover\/tabs');\n    var res = null;\n    var cacheData = '';\n    var sourceItem = null;\n    var result = [];\n    var tab;\n    var count = 0;\n    var i;\n    var u;\n\n    try {\n        cacheData = cache.get(dateT)+\"1\";\n\n        if (cacheData) {\n            try {\n                res = JSON.parse(cacheData);\n            } catch (e) {\n                res = null;\n            }\n        }\n\n        if (!res) {\n            res = JSON.parse(java.ajax(url));\n\n            if (res && res.code == 0) {\n                cache.put(dateT, JSON.stringify(res));\n            }\n        }\n    } catch (e) {\n        return [{\n            title: '数据加载失败，请刷新后重试',\n            url: '',\n            style: {\n                layout_flexGrow: 1,\n                layout_flexBasisPercent: 1\n            }\n        }];\n    }\n\n    if (!res || res.code != 0 || !res.data || !res.data.sources) {\n        return [{\n            title: '请先登陆，登陆后刷新发现页即可',\n            url: '',\n            style: {\n                layout_flexGrow: 1,\n                layout_flexBasisPercent: 1\n            }\n        }];\n    }\n\n    for (i = 0; i < res.data.sources.length; i++) {\n        if (res.data.sources[i] && res.data.sources[i].name == so) {\n            sourceItem = res.data.sources[i];\n            break;\n        }\n    }\n\n    if (!sourceItem || !sourceItem.tabs || sourceItem.tabs.length == 0) {\n        return [{\n            title: '暂无' + (so || '') + '发现内容',\n            url: '',\n            style: {\n                layout_flexGrow: 1,\n                layout_flexBasisPercent: 1\n            }\n        }];\n    }\n\n    for (i = 0; i < sourceItem.tabs.length; i++) {\n        tab = sourceItem.tabs[i];\n\n        if (!tab) {\n            continue;\n        }\n\n        if (tab.section) {\n            if (count > 0) {\n                while (count < 3) {\n                    result.push({\n                        title: '--',\n                        url: '',\n                        style: {\n                            layout_flexGrow: 1,\n                            layout_flexBasisPercent: 0.25\n                        }\n                    });\n                    count++;\n                }\n            }\n\n            result.push({\n                title: tab.title || '',\n                url: '',\n                style: {\n                    layout_flexGrow: 1,\n                    layout_flexBasisPercent: 1\n                }\n            });\n\n            count = 0;\n            continue;\n        }\n\n        u = '\/api\/discover\/content?source='\n            + encodeURIComponent(sourceItem.source || '')\n            + '&tab='\n            + encodeURIComponent(tab.key || '')\n            + '&page={{page}}&page_size=12';\n\n        result.push({\n            title: tab.title || '',\n            url: Api(u),\n            style: {\n                layout_flexGrow: 1,\n                layout_flexBasisPercent: 0.25\n            }\n        });\n\n        count++;\n\n        if (count >= 3) {\n            count = 0;\n        }\n    }\n\n    if (count > 0) {\n        while (count < 3) {\n            result.push({\n                title: '--',\n                url: '',\n                style: {\n                    layout_flexGrow: 1,\n                    layout_flexBasisPercent: 0.25\n                }\n            });\n\n            count++;\n        }\n    }\n\n    return result;\n}\n\nvar so = cache.get('sources') || '起点小说';\n\nvar s = [\n    create(\n        \"请选择平台\",\n        [\"番茄小说\", \"七猫小说\", \"书旗小说\", \"塔读小说\",\"红烛故事\",\"西瓜小说\",\"轻小说\",\"星星短剧\",\"依依短剧\",\"起点小说\"],\n        so,\n        \"sources\",\n        1\n    )\n];\n\n\n\nJSON.stringify(s.concat(styles(so)), null, 2);\n<\/js>","ruleExplore":{"bookList":"","name":"","author":"","kind":"","wordCount":"","lastChapter":"","intro":"","coverUrl":"","bookUrl":"","updateTime":""},"ruleBookInfo":{"init":"<js>\nlet url = java.hexDecodeToString(result);\njava.ajax(Api(url));\n<\/js>","name":"$.data.name","author":"$.data.author","kind":"{{$.data.category}},{{$.data.status}}","wordCount":"","lastChapter":"","intro":"<js>\nresult = JSON.parse(result);\n\nlet typeM = {\n\t\"novel\" : \"小说\",\n\t\"audio\" : \"听书\",\n\t\"image\" : \"漫画\",\n\t\"video\" : \"短剧\"\n\t}\n\nconst {\n  source: bookSource,\n  latest_chapter,\n  latest_update_time,\n  description,\n  type: sourceType\n} = result.data;\n\n[\n  `  源站：${bookSource}`,\n  latest_chapter && `最新章节：${latest_chapter}`,\n  latest_update_time && `更新时间：${formatDate(latest_update_time)}`,\n  `类型：${typeM[sourceType] || '小说'}`,\n  \"\\n\",\n  description\n].filter(Boolean).join('\\n')\n<\/js>","coverUrl":"","tocUrl":"\/api\/book\/chapters?source={{$.data.source}}&book_id={{$.data.id}}&type={{$.data.type}}\n<js>\n`data:;base64,${java.base64Encode(result)},{\"type\":\"mw\"}`\n<\/js>","canReName":"","downloadUrls":"","updateTime":""},"ruleToc":{"preUpdateJs":"","chapterList":"<js>\nlet url = java.hexDecodeToString(result);\nlet resStr = java.ajax(Api(url));\nlet res = JSON.parse(resStr);\nlet sourceType = url.match(\/type=([^&]+)\/)[1];\njava.put('sourceType',sourceType);\n\n\nif (res.code != 0) {\n  const parts = book.bookUrl.split(',')[1];\n  const decodedUrl = java.base64Decode(parts);\n  resStr = java.ajax(Api(decodedUrl.replace('book\/detail', 'book\/chapters')));\n}\n\nconst typeMap = {\n    \"novel\": {\n        ios: 0,\n        default: 8\n    },\n    \"audio\": {\n        ios: 1,\n        default: 32\n    },\n    \"image\": {\n        ios: 2,\n        default: 64\n    },\n    \"video\": {\n        ios: 3,\n        default: 4\n    }\n};\nconst currentType = typeMap[sourceType] || typeMap[\"novel\"];\nif (Env==3) {\nbook.type = currentType.ios;\n} else {\nbook.type = currentType.default;\n}\n\nresStr;\n<\/js>\n$.data.chapters","chapterName":"$.name","chapterUrl":"\/api\/chapter\/content?source={{$.source}}&chapter_id={{$.id}}&type={{java.get('sourceType')}}\n<js>\n`data:;base64,${java.base64Encode(result)},{\"type\":\"mw\"}`\n<\/js>","formatJs":"","isVolume":"","isVip":"","isPay":"","nextTocUrl":"","updateTime":"$.update_time\n<js>\nformatDate(result)\n<\/js>","wordCount":""},"ruleContent":{"content":"<js>\nlet url = java.hexDecodeToString(result);\njava.log(url)\nresult = java.ajax(Api(url));\nresult = JSON.parse(result);\n\nlet content;\nlet code = result.code;\nlet msg = result.message;\n\nlet sourceType = url.match(\/type=([^&]+)\/)[1];\n\nif (code != 0) {\n  content = msg;\n} else if (sourceType && sourceType==\"novel\") {\n  content = Content(result)\n} else {\n\tcontent = result.data.content;\n\t}\n\t\n<\/js>","title":"","nextContentUrl":"","webJs":"","sourceRegex":"","replaceRegex":"","subContent":"","imageStyle":"","imageDecode":"","payAction":"","callBackJs":""},"lastUpdateTime":"1790609782867"}]