🌞晴天融合4.11.9(vip完全版)

晴天融合VIP4.0

晴天 (8653)3天前

全网最全聚合书源,支持30+主流平台
二维码导入
{
    "bookSourceComment": "更新日志请点击登录,更新书源中查看\n\n兼容正式版阅读app",
    "bookSourceGroup": "晴天聚合",
    "bookSourceName": "🌞晴天融合4.11.9(vip完全版)",
    "bookSourceType": 0,
    "bookSourceUrl": "晴天融合VIP4.0",
    "bookUrlPattern": "https?:\\\/\\\/(?:[a-zA-Z0-9]+\\.)*(?:qingtian618\\.com|gyks\\.cf)\\\/detail.*",
    "customButton": false,
    "customOrder": -1,
    "enabled": true,
    "enabledCookieJar": false,
    "enabledExplore": true,
    "eventListener": false,
    "exploreUrl": "<js>\nfunction setArgument(key, value) {\n    var open_argument = source.getVariable();\n    open_argument = getArguments(open_argument, '') || {};\n    open_argument[key] = value;\n    var result = JSON.stringify(open_argument);\n    source.setVariable(result);\n    return result;\n}\n\nvar open_argument = source.getVariable();\nvar base_url = getArguments(open_argument, 'server') || '';\nvar ms = getArguments(open_argument, 'tone_id') || '';\nvar source_type = getArguments(open_argument, 'source_type') || '男频';\nvar tab = getArguments(open_argument, 'media') || '小说';\nvar sources = getArguments(open_argument, 'source') || '番茄';\n\n\nvar sdtoken;\ntry {\n    var loginInfoMap = source.getLoginInfoMap ? source.getLoginInfoMap() : {};\n    sdtoken = String(loginInfoMap['手动填写番茄token(可不填)'] || '');\n} catch (e) {\n    sdtoken = '';\n}\n\nvar rawCookie = getFanqieCookie() || sdtoken;\nvar match = rawCookie.match(\/sessionid=[^;]+\/);\nvar fqcookie = match ? match[0] : '';\nvar fqssionid = '';\nif (!fqcookie) {\n    java.toast('您还未登陆番茄账号,无法同步数据哦!');\n} else {\n    fqssionid = getSessionId(fqcookie)\n}\nvar fqsjurl = base_url + \"\/bookshelf?page={{page}}&ssionid=\" + fqssionid;\nvar fqtjurl = base_url + \"\/fqrecommend?page={{page}}&ssionid=\" + fqssionid;\nvar fqlsurl = base_url + \"\/fqhistory?page={{page}}&ssionid=\" + fqssionid;\n\nvar groupDatas = [];\nvar infoData = [];\n\nfunction deviceType() {\n    try {\n        return !!java.androidId();\n    } catch (e) {\n        return false;\n    }\n}\n\nvar hasValidCookie = fqcookie.length > 0;\n\nif (hasValidCookie) {\n    function groupQuery() {\n        try {\n            var url = base_url + \"\/group_name?ssionid=\" + fqssionid;\n            var res = java.ajax(url);\n            var response = JSON.parse(res);\n\n            if (!(response && response.data)) {}\n\n            response.data.forEach(function(group) {\n                var keys = Object.keys(group);\n                if (keys.length > 0) {\n                    var key = keys[0];\n                    var value = group[key];\n                    if (value && value.length) {\n                        var option = {\n                            \"method\": \"POST\",\n                            \"body\": {\n                                \"book_ids\": value,\n                                \"page\": \"{{page}}\"\n                            }\n                        };\n                        groupDatas.push({\n                            title: key,\n                            url: base_url + \"\/bookshelf,\" + JSON.stringify(option),\n                            style: {\n                                layout_flexGrow: 1,\n                                layout_flexBasisPercent: 0.45\n                            }\n                        });\n                    }\n                }\n            });\n\n            if (groupDatas.length % 2 !== 0) {\n                groupDatas.push({\n                    title: \"--\",\n                    url: \"\",\n                    style: {\n                        layout_flexGrow: 1,\n                        layout_flexBasisPercent: 0.45\n                    }\n                });\n            }\n        } catch (e) {\n            java.longToast(\"番茄登录过期,已隐藏番茄书架\");\n        }\n    }\n\n    try {\n        java.longToast(\"正在加载分组数据...\");\n        var userUrl = base_url + \"\/fquser?ssionid=\" + fqssionid;\n        var userRes = java.ajax(userUrl);\n        var userData = JSON.parse(userRes);\n\n        var userName = (userData && userData.data && userData.data.name) ? userData.data.name : '未知用户';\n        if (!userName.includes('未知用户')) {\n            infoData = [{\n                title: userName + \"个人中心\",\n                url: fqsjurl,\n                style: {\n                    layout_flexGrow: 1,\n                    layout_flexBasisPercent: 1\n                }\n            }, {\n                title: \"个性推荐(番茄)\",\n                url: fqtjurl,\n                style: {\n                    layout_flexGrow: 1,\n                    layout_flexBasisPercent: 0.45\n                }\n            }, {\n                title: \"历史阅读(番茄)\",\n                url: fqlsurl,\n                style: {\n                    layout_flexGrow: 1,\n                    layout_flexBasisPercent: 0.45\n                }\n            }];\n        }\n        groupQuery();\n    } catch (e) {\n        java.longToast(\"番茄登录过期,已隐藏番茄书架\");\n    }\n}\n\nvar style_list = [];\ntry {\n    var durl = `${base_url}\/discovestyle?source=${sources}&source_type=${source_type}&tab=${tab}`;\n    var res = java.ajax(durl);\n    var result = JSON.parse(res);\n    style_list = result.data || [];\n    if (result.msg) {\n        java.toast(result.msg);\n    }\n} catch (e) {\n    java.toast(\"发现样式获取失败\");\n}\n\nvar finalData = infoData.concat(groupDatas, style_list);\nJSON.stringify(finalData);\n<\/js>",
    "header": "{ \"User-Agent\":\"Mozilla\/5.0 (Linux; Android 6.0; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Mobile Safari\/537.36 Edg\/138.0.0.0\" }",
    "jsLib": "var host = [\n    'https:\/\/v1.gyks.cf',\n    'https:\/\/v2.gyks.cf',\n    'https:\/\/v3.gyks.cf',\n    'https:\/\/v4.gyks.cf',\n    'https:\/\/v5.gyks.cf',\n    'https:\/\/v6.gyks.cf',\n    'https:\/\/v7.gyks.cf',\n    'http:\/\/101.35.133.34:8888',\n    'http:\/\/103.236.91.147:8888'\n];\n\nfunction getArguments(open_argument, key) {\n    try {\n        open_argument = JSON.parse(open_argument);\n    } catch (e) {\n        open_argument = {\n            media: \"小说\",\n            tone_id: \"默认音色\",\n            server: host[0],\n            source: \"全部\",\n            source_type: \"男频\",\n        };\n    }\n    if (key) {\n        return open_argument[key];\n    } else {\n        return open_argument;\n    }\n}\n\nfunction setArguments(key, value) {\n    const {\n        source\n    } = this;\n    let open_argument = source.getVariable();\n    open_argument = getArguments(open_argument, '');\n    open_argument[key] = value;\n    open_argument = JSON.stringify(open_argument);\n    source.setVariable(open_argument);\n    return open_argument;\n}\n\nfunction decrypt(Text) {\n    return Text;\n}\n\nfunction paraForAndroid(content, sources) {\n    let {\n        java,\n        cache,\n        source\n    } = this;\n    let plcolor = getArguments(source.getVariable(), \"plcolor\");\n    if (!plcolor) {\n        plcolor = \"#000000\";\n    }\n\n    const createSvg = this.createSvg.bind(this);\n\n    return content.replace(\/<p>(.*?)(?:<comment ident=\"([^\"]*)\" count=\"([^\"]*)\" \\\/>)?<\\\/p>\/g,\n        (match, text, url, count) => {\n            if (url && count) {\n                const click = 0;\n                cache.putMemory(url, click);\n                const encodedUrl = url;\n                return `<p>${text}<img src=\"${createSvg(count, plcolor,encodedUrl,sources)}\"><\/p>`;\n            } else {\n                return `<p>${text}<\/p>`;\n            }\n        }\n    );\n}\n\n\nfunction showCmt(url, sources) {\n    let {\n        java,\n        cache\n    } = this;\n\n    const currentTime = Date.now();\n    const click = cache.getFromMemory(url);\n    let isqread = false;\n    try {\n        java.qread();\n        isqread = true;\n    } catch (e) {}\n    if (click < 1 && !isqread) {\n        cache.putMemory(url, click + 1);\n        return;\n    } else {\n        try {\n            java.startBrowserDp(url, sources + '段评');\n        } catch (e) {\n            java.startBrowser(url, sources + '段评');\n        }\n    }\n}\n\n\n\nfunction createSvg(number, color, encodedUrl, sources) {\n    var displayText = number > 99 ? \"99+\" : number.toString();\n    var loginInfoMap = {};\n\n    if (this.source && typeof this.source.getLoginInfoMap == 'function') {\n        loginInfoMap = this.source.getLoginInfoMap() || {};\n    }\n\n    var bubbleStyle = String(loginInfoMap['段评气泡样式'] || '0');\n    var svg;\n\n    \/\/ 样式1:精致圆形 - 简洁优雅\n    if (bubbleStyle == '1') {\n        svg = '<svg width=\"1000\" height=\"1000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n            '<circle cx=\"500\" cy=\"500\" r=\"440\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"32\" opacity=\"0.2\"\/>' +\n            '<circle cx=\"500\" cy=\"500\" r=\"440\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"4\"\/>' +\n            '<text x=\"500\" y=\"500\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n            'font-size=\"400\" fill=\"' + color + '\" dy=\"0.35em\" font-weight=\"500\">' + displayText + '<\/text>' +\n            '<\/svg>';\n    }\n    \/\/ 样式2:微信风格 - 熟悉亲切的对话气泡\n    else if (bubbleStyle == '2') {\n        svg = '<svg width=\"1000\" height=\"900\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n            '<path d=\"M120,120 L880,120 Q920,120 920,160 L920,680 Q920,720 880,720 L280,720 L120,840 L120,720 Q80,720 80,680 L80,160 Q80,120 120,120 Z\" ' +\n            'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"24\" stroke-linejoin=\"round\"\/>' +\n            '<text x=\"500\" y=\"440\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n            'font-size=\"360\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"500\">' + displayText + '<\/text>' +\n            '<\/svg>';\n    }\n    \/\/ 样式3:悬浮标签 - 扁平现代风格\n    else if (bubbleStyle == '3') {\n        svg = '<svg width=\"1000\" height=\"600\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n            '<rect x=\"80\" y=\"80\" width=\"840\" height=\"440\" rx=\"220\" ry=\"220\" ' +\n            'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"6\"\/>' +\n            '<rect x=\"100\" y=\"100\" width=\"800\" height=\"400\" rx=\"200\" ry=\"200\" ' +\n            'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"20\" opacity=\"0.3\"\/>' +\n            '<text x=\"500\" y=\"310\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n            'font-size=\"280\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"500\" letter-spacing=\"8\">' + displayText + '<\/text>' +\n            '<\/svg>';\n    }\n    \/\/ 样式4:书签标注 - 符合阅读场景\n    else if (bubbleStyle == '4') {\n        svg = '<svg width=\"900\" height=\"1000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n            '<path d=\"M150,80 L750,80 Q800,80 800,130 L800,870 Q800,920 750,920 L480,920 L450,980 L420,920 L150,920 Q100,920 100,870 L100,130 Q100,80 150,80 Z\" ' +\n            'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"24\" stroke-linejoin=\"round\"\/>' +\n            '<line x1=\"150\" y1=\"280\" x2=\"750\" y2=\"280\" stroke=\"' + color + '\" stroke-width=\"3\" opacity=\"0.3\"\/>' +\n            '<text x=\"450\" y=\"520\" font-family=\"Georgia, serif\" text-anchor=\"middle\" ' +\n            'font-size=\"360\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"400\">' + displayText + '<\/text>' +\n            '<text x=\"450\" y=\"800\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n            'font-size=\"70\" fill=\"' + color + '\" opacity=\"0.6\" letter-spacing=\"3\">评论<\/text>' +\n            '<\/svg>';\n    }\n    \/\/ 默认返回样式0\n    else {\n        svg = '<svg width=\"160\" height=\"120\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n            '<path d=\"M 55 10 ' +\n            'L 120 10 ' +\n            'Q 150 10 150 40 ' +\n            'L 150 80 ' +\n            'Q 150 110 120 110 ' +\n            'L 55 110 ' +\n            'Q 25 110 25 80 ' +\n            'L 25 75 ' +\n            'L 3 60 ' +\n            'L 25 45 ' +\n            'L 25 40 ' +\n            'Q 25 10 55 10 Z\" ' +\n            'fill=\"none\" ' +\n            'stroke=\"' + color + '\" ' +\n            'stroke-width=\"2\" ' +\n            'stroke-linejoin=\"round\"\/>' +\n            '<!-- 数字文本 -->' +\n            '<text x=\"87\" y=\"75\" ' +\n            'font-family=\"Arial, sans-serif\" ' +\n            'text-anchor=\"middle\" ' +\n            'dominant-baseline=\"middle\" ' +\n            'font-size=\"50\" ' +\n            'font-weight=\"bold\" ' +\n            'fill=\"' + color + '\">' +\n            displayText +\n            '<\/text>' +\n            '<!-- 提示文本 -->' +\n            '<text x=\"87\" y=\"95\" ' +\n            'font-family=\"Arial, sans-serif\" ' +\n            'text-anchor=\"middle\" ' +\n            'dominant-baseline=\"middle\" ' +\n            'font-size=\"9\" ' +\n            'fill=\"' + color + '\" ' +\n            'opacity=\"0.7\">' +\n            '刷新查看' +\n            '<\/text>' +\n            '<\/svg>';\n    }\n\n    var encodedSvg = this.java.base64Encode(svg);\n    return 'data:image\/svg+xml;base64,' + encodedSvg + ',{\"js\":\"showCmt(\\'' + encodedUrl + '\\', \\'' + sources + '\\')\",\"style\":\"text\"}';\n}\n\n\n\nfunction cleanHTML(html) {\n    let result = html\n        .replace(\/<header[^>]*>[\\s\\S]*?<\\\/header>\/gi, \"\")\n        .replace(\/<div class=\"tt-title\"[^>]*>[\\s\\S]*?<\\\/div>\/gi, \"\")\n        .replace(\/<(?!\\\/?p\\b|\\\/?img\\b)[^>]+>\/gi, \"\");\n    result = result.replace(\/<\\\/?p[^>]*>\/g, \"\\n\");\n    return result.replace(\/\\n+\/g, \"\\n\").trim();\n}\nvar javaImport = new JavaImporter();\njavaImport.importClass(\n    Packages.android.util.Base64,\n    Packages.java.lang.String,\n    Packages.java.net.URL,\n    Packages.okhttp3.HttpUrl\n);\nwith(javaImport) {\n    function btoa(data) {\n        return Base64.encodeToString(String(data).getBytes(\"UTF-8\"), 2);\n    }\n\n    function getSubDomain(url) {\n        let baseUrl = getBaseUrl(url);\n        if (!baseUrl) {\n            return url;\n        }\n        try {\n            let mURL = URL(baseUrl);\n            let host = mURL.host;\n            if (isIPAddress(host)) return host;\n            return HttpUrl.parse(baseUrl).topPrivateDomain() || host;\n        } catch (e) {\n            this.java.log(e);\n            return baseUrl;\n        }\n    }\n\n    function getDomain(url) {\n        let baseUrl = getBaseUrl(url);\n        if (!baseUrl) {\n            return url;\n        }\n        try {\n            return URL(baseUrl).host;\n        } catch (e) {\n            return baseUrl;\n        }\n    }\n    \/**\n     * 移除cookie\n     *\/\n    function removeCookie(url) {\n        const {\n            cookie\n        } = this;\n        cookie.removeCookie(url);\n        let domains = [getDomain(url), getSubDomain(url)];\n        domains.forEach((domain) => {\n            cookie.removeCookie(domain);\n        });\n    }\n}\n\nfunction getBaseUrl(url) {\n    if (!url) {\n        return null;\n    }\n    url = String(url);\n    if (url.match(\/https?:\\\/\\\/\/i)) {\n        var index = url.indexOf(\"\/\", 9);\n        return index == -1 ? url : url.substring(0, index);\n    }\n    return null;\n}\n\nfunction isIPv4Address(ip) {\n    ip = String(ip);\n    let parts = ip.split(\".\");\n    if (parts.length !== 4) return false;\n\n    for (let part of parts) {\n        if (!\/^\\d+$\/.test(part)) return false; \/\/ 必须是数字\n        if (part.length > 1 && part[0] === \"0\") return false; \/\/ 禁止前导零\n        let num = parseInt(part, 10);\n        if (num < 0 || num > 255) return false; \/\/ 范围检查\n    }\n    return true;\n}\n\nfunction isIPv6Address(ip) {\n    ip = String(ip);\n    \/\/ 处理双冒号(最多出现一次)\n    if (ip.includes(\":::\")) return false;\n    let doubleColonCount = (ip.match(\/::\/g) || []).length;\n    if (doubleColonCount > 1) return false;\n\n    \/\/ 分割成组\n    let groups = ip.split(\":\");\n    let validGroupCount = 8;\n    let actualGroupCount = groups.filter((g) => g !== \"\").length;\n\n    \/\/ 验证组数\n    if (doubleColonCount === 1) {\n        if (actualGroupCount > validGroupCount - 1) return false;\n    } else {\n        if (groups.length !== validGroupCount) return false;\n    }\n\n    \/\/ 验证每组内容\n    for (let group of groups) {\n        if (group === \"\") continue; \/\/ 跳过空组(双冒号部分)\n        if (!\/^[0-9a-fA-F]{1,4}$\/.test(group)) return false; \/\/ 1-4位十六进制\n    }\n    return true;\n}\n\nfunction isIPAddress(input) {\n    return isIPv4Address(input) || isIPv6Address(input);\n}\n\nfunction getSessionId(cookieString) {\n    const match = cookieString.match(\/sessionid=([^;]+)\/);\n    return match ? match[1] : null;\n}\n\nfunction getKey(key) {\n    let parts = key.split(\";\");\n    for (let part of parts) {\n        if (part.includes(\"qttoken\")) {\n            return part.split(\"=\")[1];\n        }\n    }\n    return \"\";\n}\n\nfunction getFanqieCookie() {\n    const {\n        cookie\n    } = this;\n    try {\n        return String(cookie.getCookie('fanqienovel.com') || java.getCookie('fanqienovel.com') || '');\n    } catch (e) {\n        return '';\n    }\n}\n\n\nfunction paraForiOS(html, sources) {\n    return html.replace(\n        \/<p>(.*?)(?:<comment ident=\"([^\"]*)\" count=\"([^\"]*)\" \\\/>)?<\\\/p>\/g,\n        function(match, text, url, count) {\n            if (url && count) {\n                const encodedUrl = url.replace(\/&\/g, '&amp;');\n                return `<span rs-native>${text}<comment count=\"${count}\" onPress=\"java.startBrowser('${encodedUrl}','${sources}段评')\"><\/span>`;\n            } else {\n                return `<span rs-native>${text}<\/span>`;\n            }\n        }\n    );\n}",
    "lastUpdateTime": "1763266128597",
    "loginUi": "[{\n        \"name\": \"邮箱\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"密码\",\n        \"type\": \"password\"\n    },\n    {\n        \"name\": \"♥登录书源\",\n        \"type\": \"button\",\n        \"action\": \"login(true)\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🍅番茄登录\",\n        \"type\": \"button\",\n        \"action\": \"fq_login()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🏝用户后台\/注册\",\n        \"type\": \"button\",\n        \"action\": \"loginqt()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \" 🔚 退出登录\",\n        \"type\": \"button\",\n        \"action\": \"logout()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🔮 检测登录\",\n        \"type\": \"button\",\n        \"action\": \"checkStatus()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n\n    }, {\n        \"name\": \" 🗑 清除设备\",\n        \"type\": \"button\",\n        \"action\": \"clearDevice()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n\n    }, {\n        \"name\": \"📑更少简介\",\n        \"type\": \"button\",\n        \"action\": \"set_info()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"📝段评开关\",\n        \"type\": \"button\",\n        \"action\": \"paracomment('fqpara')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"👨‍🦱男频发现\",\n        \"type\": \"button\",\n        \"action\": \"set_source_type('男频')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"👩‍🦰女频发现\",\n        \"type\": \"button\",\n        \"action\": \"set_source_type('女频')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"☕打赏享福利\",\n        \"type\": \"button\",\n        \"action\": \"vip()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"❇️ 更新书源\",\n        \"type\": \"button\",\n        \"action\": \"renderVersionPage()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🗂当前模式\",\n        \"type\": \"button\",\n        \"action\": \"get_media()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    }, {\n        \"name\": \"📖小说模式\",\n        \"type\": \"button\",\n        \"action\": \"set_media('小说')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🔊听书模式\",\n        \"type\": \"button\",\n        \"action\": \"set_media('听书')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🏞漫画模式\",\n        \"type\": \"button\",\n        \"action\": \"set_media('漫画')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🖲短剧模式\",\n        \"type\": \"button\",\n        \"action\": \"set_media('短剧')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"🎚切换服务器\",\n        \"type\": \"button\",\n        \"action\": \"set_server()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"♻️检测当前服务器\",\n        \"type\": \"button\",\n        \"action\": \"checkNet()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"⚕️本地\/服务器 \",\n        \"type\": \"button\",\n        \"action\": \"get_proxy()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"📌永久发布页📌\",\n        \"type\": \"button\",\n        \"action\": \"api()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"↓↓下方可切换来源用于搜索\/发现页↓↓\",\n        \"type\": \"button\",\n        \"action\": \"get_media()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    }, {\n        \"name\": \"✨️网友推荐\",\n        \"type\": \"button\",\n        \"action\": \"set_source('推荐')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"💖我来推荐\",\n        \"type\": \"button\",\n        \"action\": \"put_book()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"全部\",\n        \"type\": \"button\",\n        \"action\": \"set_source('全部')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('番茄')\",\n        'name': '番茄',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('69书吧')\",\n        'name': '69书吧',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('七猫')\",\n        'name': '七猫',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('百度')\",\n        'name': '百度',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('起点')\",\n        'name': '起点(第三方)',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('得间')\",\n        'name': '得间',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('塔读')\",\n        'name': '塔读',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('书旗')\",\n        'name': '书旗',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('QQ')\",\n        'name': 'QQ',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('猫眼')\",\n        'name': '猫眼',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('搜书神器')\",\n        'name': '搜书神器',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('得奇')\",\n        'name': '得奇',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('伪69')\",\n        'name': '伪69',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('爱下电子书')\",\n        'name': '爱下电子书',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('小米')\",\n        'name': '小米',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('星星小说')\",\n        'name': '星星小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('笔趣阁22')\",\n        'name': '笔趣阁22',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('顶点')\",\n        'name': '顶点',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('幻梦轻小说')\",\n        'name': '幻梦轻小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('江湖')\",\n        'name': '江湖',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('歪瑞古德')\",\n        'name': '歪瑞古德漫画',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('河马')\",\n        'name': '河马短剧',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('知乎')\",\n        'name': '知乎',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('vip')\",\n        'name': '下方为VIP专属书源(点击此处搜所有vip)',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    }, {\n        'action': \"set_source('喜马拉雅')\",\n        'name': '喜马拉雅',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('懒人听书')\",\n        'name': '懒人听书',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('svip')\",\n        'name': '下方为SVIP专属书源(点击此处搜所有svip)',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    }, {\n        'action': \"set_source('超会专属短剧')\",\n        'name': '超会专属短剧',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('超会专属小说')\",\n        'name': '超会专属小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('番薯小说')\",\n        'name': '番薯小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('QQ阅读')\",\n        'name': 'QQ(会员书籍免费)',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('阅友小说')\",\n        'name': '阅友小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('好看漫画')\",\n        'name': '好看漫画',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('全本小说')\",\n        'name': '全本小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('神书网')\",\n        'name': '神书网',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('读全本')\",\n        'name': '读全本',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('八一中文网')\",\n        'name': '八一中文网',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('斋书苑')\",\n        'name': '斋书苑',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('101看书')\",\n        'name': '101看书',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('万相书城')\",\n        'name': '万相书城',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('轻小说文库')\",\n        'name': '轻小说文库',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('轻之文库')\",\n        'name': '轻之文库',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('飞速中文')\",\n        'name': '飞速中文',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('中华典藏')\",\n        'name': '中华典藏',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('毒舌影视')\",\n        'name': '毒舌影视',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('福利小说')\",\n        'name': '福利小说',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        'action': \"set_source('福利漫画')\",\n        'name': '福利漫画',\n        'type': 'button',\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    }, {\n        \"name\": \"自定义搜索源(多个用英文,分割)\",\n        \"type\": \"text\"\n    }, {\n        \"name\": \"听书Ai音色填写后点击右上角✔\",\n        \"type\": \"text\"\n    }, {\n        \"name\": \"自定义服务器(可不填)\",\n        \"type\": \"text\"\n    }, {\n        \"name\": \"自定义评论颜色(可不填)\",\n        \"type\": \"text\"\n    }, {\n        \"name\": \"段评气泡样式\",\n        \"type\": \"text\"\n    }, {\n        \"name\": \"手动填写番茄token(可不填)\",\n        \"type\": \"text\"\n    }\n]",
    "loginUrl": "\/\/ 当前书源版本号,切勿修改,否则影响更新的识别\nconst localVersion = '4.11.9';\n\nfunction login(flag) {\n    if (flag == undefined) {\n        result = JSON.parse(source.getLoginInfo())\n    } else {\n        java.longToast(\"\\n\\n💞正在登录中...\")\n        putLoginInfo(JSON.stringify(result))\n    }\n    let base_url = getArgument('server')\n    let zdyserver = String(result['自定义服务器(可不填)']);\n    if (zdyserver.includes('http')) {\n        setArgument('server', zdyserver);\n        if (getKey(String(cookie.getCookie(base_url)))) {\n            let cookies = cookie.getCookie(base_url)\ntry{removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n            cookie.setCookie(zdyserver, cookies)\n        }\n        java.toast(`\\n\\n当前服务器为自定义服务器\\n${zdyserver}\\n\\n切换服务器请先清空服务器地址中的数据`);\n    }\n    let zdytone_id = String(result['听书Ai音色填写后点击右上角✔'] || '');\n    if (zdytone_id) {\n        setArgument('tone_id', zdytone_id);\n    } else {\n        setArgument('tone_id', '默认音色');\n    }\n    let plcolor = String(result['自定义评论颜色(可不填)'] || '#000000');\n    if (plcolor) {\n        setArgument('plcolor', plcolor);\n    } else {\n        setArgument('plcolor', '#000000');\n    }\n    let zdysources = String(result['自定义搜索源(多个用英文,分割)'] || '');\n    if (zdysources) {\n        setArgument('source', zdysources);\n    };\n    base_url = getArgument('server')\n    let register_email = String(result['邮箱'])\n    let password = String(result['密码'])\n    let key = String(result['密钥'] || '')\n\n    \/\/java.log(cookie.getCookie(base_url))\n    if ((register_email && password || key) && !String(getKey(String(cookie.getCookie(base_url))))) {\n        try{removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n        let deviceKey = '';\n        try {\n            deviceKey = java.deviceID();\n        } catch (e) {\n            deviceKey = java.androidId();\n        };\n        let deviceId = deviceKey;\n        if (register_email && password) {\n            let options = JSON.stringify({\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application\/json'\n                },\n                body: JSON.stringify({\n                    register_email: result['邮箱'],\n                    password: result['密码']\n                })\n            })\n            try {\n                let data = JSON.parse(java.ajax(`${base_url}\/login_api,${options}`))\n                if (data.code == 0) {\n                    \/\/java.toast(deviceId)\n                    java.toast(\"\\n\\n✅️登录成功\")\n                    cookie.setCookie(base_url, `qttoken=${data.key};deviceId=${deviceId}`)\n                    result['密钥'] = data.key\n                    putLoginInfo(JSON.stringify(result))\n                } else {\n                    java.toast('\\n\\n💔' + data.msg || \"登录失败,请重试!\")\n                }\n            } catch (e) {\n                java.toast(\"\\n\\n💔登录失败,请重试!\\n\" + e.message)\n            }\n        } else {\n            cookie.setCookie(base_url, `qttoken=${key};deviceId=${deviceId}`)\n            let res = java.ajax(`${base_url}\/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n            try {\n                res = JSON.parse(res)\n                if (res.id != undefined) {\n                    java.toast('\\n\\n密钥登录成功')\n                    result['邮箱'] = res.email\n                    putLoginInfo(JSON.stringify(result))\n                } else {\n                    throw new Error()\n                }\n            } catch (e) {\n                java.log(e)\n                java.toast(\"\\n\\n💔登录失败\")\n            }\n        }\n    } else if (flag && String(getKey(String(cookie.getCookie(base_url))))) {\n        java.toast(\"\\n\\n当前✅️已登录,请🚫退出登录后重新登录\");\n        \/\/checkStatus();\n    } else if (flag) {\n        java.toast(\"\\n\\n⛔️请先填写邮箱和密码\");\n    }\n}\n\n\/\/ 检测服务器\nfunction checkNet() {\n    let url = getArgument('server');\n    java.longToast(`\\n\\n♻️正在检测:${url}\\n请稍等~`);\n    let date1 = new Date().getTime();\n    let html = java.ajax(url + '\/login');\n    let date2 = new Date().getTime();\n    let t = date2 - date1;\n    let c = String(html).indexOf('晴天');\n    let code = 1;\n    let time = t \/ 1000 + 's';\n    let logTime = '【' + url + '】\\n┋┋\\n' + '解析时间:' + time;\n    if (c == -1 || t > 5000) {\n        java.longToast('\\n💔【访问失败提示】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♣️当前接口无法访问(可能被墙)♣️\\n┋┋\\n请切换其他接口\/切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n    } else if (t < 1000) {\n        java.longToast('\\n💖【网络环境优良】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n❤️延迟低,推荐使用此接口❤️\\n┋┋\\n网络环境优良,请继续保持状态\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n    } else if (t >= 1000 && t < 2000) {\n        java.longToast('\\n💛【网络环境一般】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♦️延迟一般,勉强可使用♦️\\n┋┋\\n请切换其他接口或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n    } else if (t >= 2000 && t < 5000) {\n        java.longToast('\\n💔【网络环境堪忧】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♠延迟过高,不建议使用♠\\n┋┋\\n请切换其他接口或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n    }\n}\n\nfunction isVips(res) {\n    let isVIP = '';\n    let vipEndTime = res.vip_end_time;\n    let formattedDate = '';\n\n    if (vipEndTime && vipEndTime !== 0) {\n        let date = new Date(vipEndTime * 1000);\n        formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;\n        let currentTime = Math.floor(Date.now() \/ 1000);\n        let remainingDays = Math.ceil((vipEndTime - currentTime) \/ (24 * 60 * 60));\n        if (currentTime > vipEndTime) {\n            isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} (已过期)`;\n        } else if (remainingDays <= 7) {\n            isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} 剩余${remainingDays}天`;\n        } else {\n            if (vipEndTime < 1912946812) {\n                isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"}(${formattedDate})`;\n            } else {\n                isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} (永久)`;\n            }\n        }\n    } else {\n        isVIP = '您尚未开通VIP';\n    }\n    return isVIP;\n}\n\nfunction checkStatus() {\n    java.longToast('\\n\\n♻️检测中...');\n    let base_url = getArgument('server')\n    let res = java.ajax(`${base_url}\/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n    try {\n        res = JSON.parse(res)\n        if (res.id != undefined) {\n            result['邮箱'] = res.email\n            putLoginInfo(JSON.stringify(result))\n            let devices\n            try {\n                devices = JSON.parse(res.device).length;\n            } catch (e) {\n                devices = res.device ? 1 : 0;\n            }\n            let isVip = isVips(res);\n            tips = `\n┏┅┅┅┅┅┅┱┄┄┄┄┄┄┄┄┄┄┐\n  🧢昵称     ${res.nickname.padEnd(20,\"\\t\") || \"未设置\".padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n ✉️邮箱    ${res.email.replace(\/(.{3}).*?@\/,\"$1***@\").padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🔑密钥    ${(`${res.user_key.substring(0,4)}***${res.user_key.slice(-4)}`).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📅注册时间  ${java.timeFormat(res.register_time*1000).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🗒️今日阅读  ${(java.timeFormat(new Date()).slice(0,10)==java.timeFormat(res.last_read_time * 1000).slice(0,10)?res.day_read_count:0).toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📚累计阅读  ${res.all_read_count.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🕓最后阅读  ${(res.last_read_time != 0?java.timeFormat(res.last_read_time * 1000):'未阅读').padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📱关联设备  ${devices.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 👑会员状态  ${isVip.padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🚫封禁状态  ${res.is_banned?'已封禁':'正常 '}       \n┗┅┅┅┅┅┅┹┄┄┄┄┄┄┄┄┄┄┘\n`\n            java.log(tips)\n            java.longToast(tips)\n        } else {\n            throw new Error(res.msg)\n        }\n    } catch (e) {\n        \/\/java.log(e)\n        java.toast(\"\\n检测登录失败\\n\" + e.message)\n    }\n}\n\nfunction clearDevice() {\n    let base_url = getArgument('server')\n    let res = java.ajax(`${base_url}\/clear,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n    java.toast(res.code === 0 ? \"\\n\\n📴设备清除成功\" : res.msg)\n    Packages.java.lang.Thread.sleep(500)\n    checkStatus()\n}\n\/\/ 保存登录UI信息\nfunction putLoginInfo(info) {\n    try {\n        let key = java.androidId()\n        let encodeStr = Packages.android.util.Base64.encodeToString(java.createSymmetricCrypto(\"AES\", key).encrypt(info), 2)\n        cache.put(`userInfo_${source.getKey()}`, encodeStr)\n        return true\n    } catch (e) {\n        java.log(e)\n        return source.putLoginInfo(info)\n    }\n}\n\n\/\/ 填写密钥\nfunction loginqt() {\n    java.startBrowserAwait(getArgument('server') + '\/login', '登录晴天小说书源');\n}\n\n\/\/登录番茄\nfunction fq_login() {\n    try {\n        java.startBrowserAwait(\"https:\/\/fanqienovel.com\/\", \"登录\")\n    } catch (e) {\n        java.toast(e)\n    }\n    try {\n        cookie.removeCookie(\"snssdk.com\")\n    } catch (e) {}\n    var cookie_ = \"sessionid=\" + (String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) ? String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) : source.getLoginInfoMap()['手动登录Token'])\n    let user\n    try {\n        user = JSON.parse(java.ajax(\"https:\/\/fanqienovel.com\/api\/user\/info\/v2,\" + JSON.stringify({\n            method: \"GET\",\n            headers: {\n                \"Cookie\": cookie_\n            }\n        }))).data.name\n    } catch (e) {\n        java.log(e)\n    }\n    if (!cookie_ || cookie_ == \"sessionid=\" || !user) {\n        java.toast(\"未获取到登录凭据,登录失败\")\n        return false\n    }\n    java.toast(\"\\n\\n欢迎 \" + user + \"\\n登录成功!\")\n    return true\n}\n\n\/\/退出登录\nfunction logout() {\n    cookie.removeCookie(\"fanqienovel.com\");\n    cookie.removeCookie(\"snssdk.com\");\n    cookie.removeCookie(\"69shuba.com\");\n    \/*\n    let servers = host\n    for (let server of servers) {\n    \ttry{removeCookie(server )} catch(e){cookie.removeCookie(server )}\n    }\n    *\/\ntry{removeCookie(getArgument('server'))} catch(e){cookie.removeCookie(getArgument('server'))}\n    java.toast(\"退出登录成功\");\n}\n\n\/\/获取参数\nfunction getArgument(key) {\n    let open_argument = source.getVariable();\n    open_argument = getArguments(open_argument, '');\n    return open_argument[key];\n}\n\n\/\/设置参数\nfunction setArgument(key, value) {\n    let open_argument = source.getVariable();\n    open_argument = getArguments(open_argument, '');\n    open_argument[key] = value;\n    open_argument = JSON.stringify(open_argument);\n    source.setVariable(open_argument);\n    return open_argument;\n}\n\n\/\/ 设置本地or云端访问\nfunction get_proxy() {\n    let proxy = getArgument('proxy');\n    if (proxy == '本地') {\n        setArgument('proxy', '云端');\n        java.longToast('\\n所有数据采用\\n\\n服务器网络访问\\n\\n如果发现用不了,请切换本地网络访问,如69书吧');\n    } else {\n        setArgument('proxy', '本地');\n        java.longToast('\\n所有数据采用\\n\\n本地网络访问\\n\\n如果发现用不了,请开启网络代理,如69书吧');\n    }\n}\n\n\n\/\/设置男女频\nfunction set_source_type(source_type) {\n    setArgument(\"source_type\", source_type);\n    java.toast(\"\\n发现页已设置为:\" + source_type);\n}\n\n\/\/首页\nfunction api() {\n    java.startBrowserAwait('http:\/\/vip.gyks.cf', \"首页\");\n}\n\n\/\/打赏\nfunction vip() {\n    java.startBrowserAwait(getArgument('server') + '\/coffee', \"喝咖啡\");\n}\n\nvar server = getArgument('server');\n\n\/\/设置搜索媒体\nfunction set_media(media) {\n    const mediaConfig = {\n        '喜马拉雅': ['听书'],\n        '番茄': '*',\n        '福利小说': ['小说'],\n        '如漫画': ['漫画'],\n        '包子漫画': ['漫画'],\n        '九妖漫画': ['漫画'],\n        '绅士漫画': ['漫画'],\n        '福利漫画': ['漫画'],\n        '好看漫画': ['漫画'],\n        '六月听书': ['听书'],\n        '海洋听书': ['听书'],\n        '七猫': ['小说', '听书', '短剧'],\n        '河马': ['短剧'],\n        '超会专属短剧': ['短剧'],\n        '歪瑞古德': ['漫画'],\n        '毒舌影视': ['短剧'],\n        '全部': '*', \/\/ 允许所有模式\n        '默认': ['小说']\n    };\n\n    const source = getArgument('source');\n    const allowedModes = mediaConfig[source] || mediaConfig['默认'];\n    let targetMedia = mediaConfig['默认'][0];\n    let isAllowed = false;\n\n    if (allowedModes === '*' || allowedModes.includes(media)) {\n        targetMedia = media;\n        isAllowed = true;\n    } else if (Array.isArray(allowedModes)) {\n        targetMedia = allowedModes[0];\n    }\n\n    const message = isAllowed ?\n        `\\n\\n已切换至:${targetMedia}\\n请重新搜索书籍!` :\n        `\\n\\n目前${source}:不支持【${media}】模式!\\n已自动切换至:${targetMedia}`;\n\n    setArgument('media', targetMedia);\n    java.toast(message);\n}\n\n\/\/获取搜索媒体\nfunction get_media() {\n    let media = getArgument('media');\n    let source = getArgument('source');\n    if (media == '') {\n        media = '全部';\n    }\n    var tishi = '\\n\\n当前服务器:' + getArgument('server')\n    java.longToast(`\\n\\n当前使用源:${source}-${media}${tishi}`);\n}\n\n\n\/\/设置服务器\nfunction set_server() {\n    putLoginInfo(JSON.stringify(result))\n    let zdyserver;\n    let base_url = getArgument('server')\n    try {\n        zdyserver = String(result['自定义服务器(可不填)']);\n        if (zdyserver.includes('http')) {\n            setArgument('server', zdyserver);\n            if (getKey(String(cookie.getCookie(base_url)))) {\n                let cookies = cookie.getCookie(base_url)\n                try{removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n                cookie.setCookie(zdyserver, cookies)\n            }\n            java.toast(`\\n\\n当前服务器为自定义服务器\\n${zdyserver}\\n\\n切换服务器请先清空服务器地址中的数据`);\n        } else {\n            zdyserver = '';\n        }\n    } catch (error) {\n        zdyserver = '';\n    }\n    if (!zdyserver) {\n        const servers = host\n        const currentServer = getArgument('server') || '';\n        const currentIndex = servers.indexOf(currentServer);\n\n        const nextIndex = currentIndex >= 0 ? (currentIndex + 1) % servers.length : 0;\n        const nextServer = servers[nextIndex];\n\n        setArgument('server', nextServer);\n        if (getKey(String(cookie.getCookie(currentServer)))) {\n            let cookies = cookie.getCookie(currentServer)\ntry{removeCookie(currentServer)} catch(e){cookie.removeCookie(currentServer)}\n            cookie.setCookie(nextServer, cookies)\n        }\n        java.longToast(`\\n\\n服务器【${nextIndex+1}】:${nextServer}`);\n    }\n}\n\n\/\/获取音色\nvar tone_id = getArgument('tone_id');\n\nfunction get_tone_id(arg) {\n    var datadist = {\n        \"0\": \"默认音色\",\n        \"-1\": \"阅读模式\",\n        \"-2\": \"漫画模式\",\n        \"51\": \"多人发音\",\n        \"1\": \"甜美少女\",\n        \"2\": \"清亮青叔\",\n        \"5\": \"开朗青年\",\n        \"6\": \"温柔淑女\",\n        \"4\": \"成熟大叔\",\n        \"74\": \"大叔升级\",\n        \"30\": \"优雅御姐\"\n    };\n    var tone_id = datadist[arg] || arg;\n    var tishi = '\\n\\n当前音色:' + tone_id;\n    java.toast(tishi);\n}\n\n\/\/设置音色\nfunction set_tone_id(mode, name) {\n    putLoginInfo(JSON.stringify(result))\n    let zdytone_id;\n    try {\n        zdytone_id = String(result['其他音色填写后点击右上角✔']);\n        if (zdytone_id) {\n            setArgument('tone_id', zdytone_id);\n            java.toast(`\\n\\n当前音色为自定义音色\\n${zdytone_id}\\n\\n切换音色请先清空音色输入框中的数据`);\n        } else {\n            zdytone_id = '';\n        }\n    } catch (error) {\n        zdytone_id = '';\n    }\n    if (!zdytone_id) {\n        let toast = \"\\n\\n已切换至:\" + name + '\\n\\n切换后需要刷新详情页';\n        setArgument('tone_id', mode);\n        java.toast(toast);\n    }\n}\n\n\/\/设置来源\nfunction set_source(sources) {\n    let zdysources = String(result['自定义搜索源(多个用英文,分割)'] || '');\n    if (zdysources.length > 1 && zdysources != 'undefined') {\n        java.toast('\\n\\n请先清空自定义源再设置');\n    } else {\n        setArgument('source', sources);\n        set_media('小说');\n        java.toast(`\\n\\n当前来源已切换为:\\n${sources}\\n\\n切换后请重新搜索`);\n    }\n}\n\n\/\/ 设置简介\nfunction set_info() {\n    var info = getArgument('info');\n    if (info == 'on') {\n        setArgument('info', 'off');\n        java.toast('\\n\\n已恢复详情页详细简介');\n    } else {\n        setArgument('info', 'on');\n        java.toast('\\n\\n已精简详情页简介');\n    }\n}\n\n\/\/ 番茄段评\nfunction paracomment() {\n    var fqpara = getArgument('fqpara');\n    if (fqpara == 'on') {\n        setArgument('fqpara', 'off');\n        java.longToast('\\n\\n段评已关闭');\n    } else {\n        setArgument('fqpara', 'on');\n        java.longToast(\"\\n\\n段评已开启\\n\\n长按刷新段后面的图片即可\\n\\n如果图片不显示,刷新无反应\\n请更新测试版阅读app\");\n    }\n}\n\n\n\/\/ 我要推荐\nfunction put_book() {\n    java.startBrowserAwait(getArgument('server') + '\/put_book', '我来推荐');\n}\n\n\/\/ 书源更新\nfunction renderVersionPage() {\n    let yd = '';\n    let html = `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/>\n  <title>书源更新<\/title>\n  <!-- Font Awesome 图标库 -->\n  <link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\" \/>\n  <style>\n    :root {\n      --primary-gradient: linear-gradient(135deg, #4e6ef2, #6b2dd8);\n      --latest-gradient: linear-gradient(135deg, #8e2de2 0%, #4a00e0 50%, #d4af37 100%);\n      --success-color: #28c76f;\n      --warning-color: #ff9f43;\n      --error-color: #ea5455;\n      --text-main: #1f2937;\n      --text-secondary: #6b7280;\n      --card-bg: #ffffff;\n      --border-color: #e5e7eb;\n      --light-bg: #f9fafb;\n      --shadow: 0 4px 12px rgba(78, 110, 242, 0.1);\n      --shadow-hover: 0 6px 18px rgba(78, 110, 242, 0.2);\n      --glow-shadow: 0 0 25px rgba(142, 45, 226, 0.5), 0 0 50px rgba(212, 175, 55, 0.3);\n      --modal-bg: rgba(31, 41, 55, 0.8);\n      --modal-content-bg: #ffffff;\n    }\n\n    * {\n      box-sizing: border-box;\n      margin: 0;\n      padding: 0;\n      font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;\n    }\n\n    body {\n      background: linear-gradient(135deg, #eef2ff, #f5f7ff);\n      color: var(--text-main);\n      min-height: 100vh;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      padding: 16px;\n    }\n\n    \/* 加载动画 *\/\n    .loading-wrapper {\n      text-align: center;\n      animation: fadeIn 0.3s ease;\n    }\n\n    .loading-spinner {\n      width: 50px;\n      height: 50px;\n      border: 4px solid rgba(78, 110, 242, 0.3);\n      border-top-color: #4e6ef2;\n      border-radius: 50%;\n      margin: 0 auto 20px;\n      animation: spin 1s linear infinite;\n    }\n\n    .loading-text {\n      color: var(--text-main);\n      font-size: 16px;\n      font-weight: 500;\n    }\n\n    @keyframes spin {\n      to { transform: rotate(360deg); }\n    }\n\n    @keyframes fadeIn {\n      from { opacity: 0; transform: translateY(20px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    @keyframes slideIn {\n      from { opacity: 0; transform: translateY(30px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    @keyframes pulse {\n      0%, 100% { opacity: 1; }\n      50% { opacity: 0.7; }\n    }\n\n    @keyframes gradientAnimation {\n      0% { background-position: 0% 50%; }\n      50% { background-position: 100% 50%; }\n      100% { background-position: 0% 50%; }\n    }\n\n    @keyframes breathe {\n      0%, 100% { \n        transform: scale(1);\n        box-shadow: var(--glow-shadow), var(--shadow);\n      }\n      50% { \n        transform: scale(1.02);\n        box-shadow: 0 0 30px rgba(142, 45, 226, 0.6), 0 0 60px rgba(212, 175, 55, 0.4), var(--shadow);\n      }\n    }\n\n    @keyframes shimmer {\n      0% {\n        background-position: -200% center;\n      }\n      100% {\n        background-position: 200% center;\n      }\n    }\n\n    \/* 主容器 *\/\n    .container {\n      width: 100%;\n      max-width: 420px;\n      background: var(--card-bg);\n      border-radius: 24px;\n      overflow: hidden;\n      box-shadow: var(--shadow);\n      position: relative;\n      z-index: 1;\n      animation: slideIn 0.5s ease;\n      display: none;\n    }\n\n    \/* 头部 *\/\n    .header {\n      background: var(--primary-gradient);\n      color: #ffffff;\n      padding: 24px 16px;\n      text-align: center;\n      position: relative;\n      overflow: hidden;\n    }\n\n    .header::before {\n      content: '';\n      position: absolute;\n      top: -30px;\n      left: -30px;\n      width: 80px;\n      height: 80px;\n      background: rgba(255, 255, 255, 0.15);\n      border-radius: 50%;\n    }\n\n    .header::after {\n      content: '';\n      position: absolute;\n      bottom: -60px;\n      right: -60px;\n      width: 150px;\n      height: 150px;\n      background: rgba(255, 255, 255, 0.1);\n      border-radius: 50%;\n    }\n\n    .header h1 {\n      font-size: 1.4rem;\n      font-weight: 700;\n      margin-bottom: 8px;\n      position: relative;\n      z-index: 2;\n    }\n\n    .header p {\n      font-size: 0.9rem;\n      opacity: 0.9;\n      line-height: 1.4;\n      position: relative;\n      z-index: 2;\n    }\n\n    .header-icon {\n      font-size: 48px;\n      margin-bottom: 10px;\n      display: inline-block;\n      animation: bounce 2s ease infinite;\n    }\n\n    @keyframes bounce {\n      0%, 100% { transform: translateY(0); }\n      50% { transform: translateY(-10px); }\n    }\n\n    \/* 版本对比 *\/\n    .version-comparison {\n      display: flex;\n      flex-wrap: nowrap;\n      gap: 12px;\n      padding: 16px;\n      margin-top: 8px;\n      position: relative;\n      z-index: 10;\n    }\n\n    .version-card {\n      flex: 1;\n      min-width: 45%;\n      background: var(--card-bg);\n      border-radius: 16px;\n      padding: 28px 16px 16px;\n      box-shadow: var(--shadow);\n      text-align: center;\n      position: relative;\n      transition: transform 0.3s ease, box-shadow 0.3s ease;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n    }\n\n    .version-card:hover {\n      transform: translateY(-4px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .version-card.current-version {\n      background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%);\n      border: 1px solid rgba(78, 110, 242, 0.15);\n    }\n\n    .version-card.current-version:hover {\n      box-shadow: 0 6px 20px rgba(78, 110, 242, 0.15);\n    }\n\n    .version-card.current-version h3,\n    .version-card.current-version .version-number,\n    .version-card.current-version .version-date {\n      color: var(--text-main);\n    }\n\n    .version-card.latest-version {\n      background: var(--latest-gradient);\n      background-size: 300% 300%;\n      box-shadow: var(--glow-shadow), var(--shadow);\n      color: #fff;\n      z-index: 2;\n      animation: gradientAnimation 6s ease infinite, breathe 3s ease-in-out infinite;\n      position: relative;\n      overflow: hidden;\n    }\n\n    .version-card.latest-version::before {\n      content: '';\n      position: absolute;\n      top: -50%;\n      left: -50%;\n      width: 200%;\n      height: 200%;\n      background: linear-gradient(\n        90deg,\n        transparent,\n        rgba(255, 255, 255, 0.3),\n        transparent\n      );\n      transform: rotate(45deg);\n      animation: shimmer 3s infinite;\n    }\n\n    .version-card.latest-version h3,\n    .version-card.latest-version .version-number,\n    .version-card.latest-version .version-date {\n      color: #fff;\n      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);\n      position: relative;\n      z-index: 1;\n    }\n\n    .version-status {\n      position: absolute;\n      top: 6px;\n      right: 6px;\n      padding: 3px 7px;\n      font-size: 0.65rem;\n      font-weight: 600;\n      border-radius: 6px;\n      color: #fff;\n      line-height: 1.2;\n      white-space: nowrap;\n      z-index: 2;\n    }\n\n    .version-card.latest-version .version-status {\n      background: rgba(255, 255, 255, 0.25);\n      backdrop-filter: blur(5px);\n      border: 1px solid rgba(255, 255, 255, 0.3);\n      color: #fff;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n    }\n\n    .status-outdated { background: var(--warning-color); }\n    .status-latest { background: var(--success-color); }\n    .status-invalid { background: var(--error-color); }\n\n    .version-card h3 {\n      font-size: 0.9rem;\n      color: var(--text-secondary);\n      margin-bottom: 8px;\n      font-weight: 500;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 6px;\n    }\n\n    .version-number {\n      font-size: 1.25rem;\n      font-weight: 700;\n      color: var(--text-main);\n      margin: 8px 0;\n      transition: all 0.3s ease;\n      font-family: 'Courier New', monospace;\n    }\n\n    .version-card.latest-version .version-number {\n      font-size: 1.4rem;\n      transform: scale(1.05);\n      text-shadow: \n        0 2px 4px rgba(0, 0, 0, 0.3),\n        0 0 10px rgba(212, 175, 55, 0.8),\n        0 0 20px rgba(212, 175, 55, 0.5);\n      animation: pulse-glow 2s ease-in-out infinite;\n    }\n\n    @keyframes pulse-glow {\n      0%, 100% {\n        text-shadow: \n          0 2px 4px rgba(0, 0, 0, 0.3),\n          0 0 10px rgba(212, 175, 55, 0.8),\n          0 0 20px rgba(212, 175, 55, 0.5);\n      }\n      50% {\n        text-shadow: \n          0 2px 4px rgba(0, 0, 0, 0.3),\n          0 0 15px rgba(212, 175, 55, 1),\n          0 0 30px rgba(212, 175, 55, 0.7);\n      }\n    }\n\n    .version-date {\n      font-size: 0.8rem;\n      color: var(--text-secondary);\n      margin-top: 4px;\n    }\n\n    \/* 版本对比指示器 *\/\n    .version-indicator {\n      position: absolute;\n      left: 50%;\n      top: 50%;\n      transform: translate(-50%, -50%);\n      z-index: 5;\n      width: 32px;\n      height: 32px;\n      border-radius: 50%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n      color: white;\n    }\n\n    .version-indicator.update-needed {\n      background: var(--error-color);\n      box-shadow: 0 2px 8px rgba(234, 84, 85, 0.4);\n      animation: pulse-indicator 1.5s infinite;\n    }\n\n    .version-indicator.is-latest {\n      background: var(--success-color);\n      box-shadow: 0 2px 8px rgba(40, 199, 111, 0.4);\n    }\n\n    @keyframes pulse-indicator {\n      0% { transform: translate(-50%, -50%) scale(1); }\n      50% { transform: translate(-50%, -50%) scale(1.1); }\n      100% { transform: translate(-50%, -50%) scale(1); }\n    }\n\n    \/* 内容区 *\/\n    .content-container {\n      padding: 16px;\n    }\n\n    \/* 状态提示 *\/\n    .status-alert {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      padding: 12px 16px;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 10px;\n      font-weight: 500;\n      font-size: 14px;\n      animation: slideIn 0.5s ease 0.3s backwards;\n    }\n\n    .status-alert i {\n      font-size: 20px;\n    }\n\n    .status-alert.update-available {\n      background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%);\n      color: #d63031;\n      box-shadow: 0 4px 15px rgba(253, 203, 110, 0.4);\n    }\n\n    .status-alert.up-to-date {\n      background: linear-gradient(135deg, #55efc4 0%, #00b894 100%);\n      color: white;\n      box-shadow: 0 4px 15px rgba(0, 184, 148, 0.4);\n    }\n\n    \/* 更新容器 *\/\n    .update-container {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      animation: slideIn 0.5s ease 0.4s backwards;\n    }\n\n    .update-header {\n      background: var(--light-bg);\n      padding: 12px 16px;\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      border-bottom: 1px solid var(--border-color);\n    }\n\n    .update-header h2 {\n      font-size: 1rem;\n      font-weight: 600;\n      color: var(--text-main);\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n\n    .update-header h2 i {\n      color: #4e6ef2;\n    }\n\n    .update-tag {\n      background: rgba(78, 110, 242, 0.1);\n      color: #4e6ef2;\n      padding: 4px 8px;\n      border-radius: 8px;\n      font-size: 0.75rem;\n      font-weight: 600;\n    }\n\n    .update-content {\n      padding: 16px;\n    }\n\n    .update-date {\n      font-weight: 600;\n      color: #4e6ef2;\n      margin-bottom: 12px;\n      display: flex;\n      align-items: center;\n      gap: 6px;\n      padding: 8px 0;\n      border-bottom: 1px dashed #e0e0e0;\n    }\n\n    .update-text {\n      margin: 8px 0;\n      position: relative;\n      padding-left: 16px;\n      line-height: 1.5;\n      color: var(--text-main);\n      font-size: 0.95rem;\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n\n    .update-text::before {\n      content: '•';\n      position: absolute;\n      left: 0;\n      font-weight: bold;\n      color: #4e6ef2;\n      font-size: 1.2rem;\n      line-height: 1;\n    }\n\n    \/* 历史日志 *\/\n    .history-container {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      animation: slideIn 0.5s ease 0.5s backwards;\n    }\n\n    .history-header {\n      background: var(--light-bg);\n      padding: 12px 16px;\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      border-bottom: 1px solid var(--border-color);\n      cursor: pointer;\n      user-select: none;\n    }\n\n    .history-header:hover {\n      opacity: 0.8;\n    }\n\n    .history-header h2 {\n      font-size: 1rem;\n      font-weight: 600;\n      color: var(--text-main);\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n\n    .history-header h2 i {\n      color: #4e6ef2;\n    }\n\n    .toggle-history {\n      background: none;\n      border: none;\n      color: var(--text-secondary);\n      cursor: pointer;\n      font-weight: 500;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n      font-size: 0.85rem;\n      transition: color 0.2s ease;\n    }\n\n    .toggle-history:hover {\n      color: #4e6ef2;\n    }\n\n    .history-content {\n      padding: 0 16px;\n      max-height: 0;\n      overflow: hidden;\n      transition: max-height 0.4s ease, padding 0.4s ease;\n    }\n\n    .history-content.expanded {\n      max-height: 60vh;\n      overflow-y: auto;\n      padding: 16px;\n      scrollbar-width: thin;\n      scrollbar-color: #4e6ef2 #f0f0f0;\n    }\n\n    .history-content.expanded::-webkit-scrollbar {\n      width: 6px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-track {\n      background: #f0f0f0;\n      border-radius: 4px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-thumb {\n      background: #4e6ef2;\n      border-radius: 4px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-thumb:hover {\n      background: #3a56d0;\n    }\n\n    .history-item {\n      margin-bottom: 16px;\n      padding-bottom: 16px;\n      border-bottom: 1px dashed var(--border-color);\n    }\n\n    .history-item:last-child {\n      border-bottom: none;\n      margin-bottom: 0;\n      padding-bottom: 0;\n    }\n\n    .history-date {\n      font-weight: 600;\n      color: var(--text-main);\n      margin-bottom: 8px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n      font-size: 0.9rem;\n      background: rgba(78, 110, 242, 0.05);\n      padding: 6px 10px;\n      border-radius: 6px;\n    }\n\n    .history-text {\n      margin: 8px 0;\n      padding-left: 16px;\n      line-height: 1.4;\n      color: var(--text-secondary);\n      position: relative;\n      font-size: 0.9rem;\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n\n    .history-text::before {\n      content: '•';\n      position: absolute;\n      left: 0;\n      color: #4e6ef2;\n      font-weight: bold;\n      font-size: 1.2rem;\n      line-height: 1;\n    }\n\n    \/* 按钮组 *\/\n    .button-group {\n      display: flex;\n      flex-direction: column;\n      gap: 10px;\n      margin-bottom: 16px;\n    }\n\n    .button {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 10px;\n      padding: 14px 28px;\n      text-align: center;\n      font-size: 1rem;\n      border: none;\n      border-radius: 12px;\n      text-decoration: none;\n      background: var(--primary-gradient);\n      color: white;\n      font-weight: 600;\n      transition: all 0.3s ease;\n      box-shadow: var(--shadow);\n      position: relative;\n      overflow: hidden;\n      cursor: pointer;\n    }\n\n    .button i {\n      font-size: 1rem;\n    }\n\n    .button::after {\n      content: '';\n      position: absolute;\n      top: -50%;\n      left: -50%;\n      width: 200%;\n      height: 200%;\n      background: rgba(255, 255, 255, 0.1);\n      transform: rotate(30deg);\n      transition: all 0.6s ease;\n      pointer-events: none;\n    }\n\n    .button:hover {\n      transform: translateY(-3px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .button:hover::after {\n      transform: rotate(30deg) translate(20%, 20%);\n    }\n\n    .button:active {\n      transform: scale(0.95);\n    }\n\n    \/* 错误状态 *\/\n    .error-state {\n      text-align: center;\n      padding: 40px 20px;\n      color: var(--text-main);\n    }\n\n    .error-icon {\n      font-size: 64px;\n      margin-bottom: 20px;\n      color: var(--error-color);\n    }\n\n    .error-text {\n      font-size: 16px;\n      line-height: 1.6;\n      margin-bottom: 20px;\n    }\n\n    .retry-button {\n      background: var(--primary-gradient);\n      color: white;\n      padding: 12px 30px;\n      border-radius: 12px;\n      border: none;\n      font-weight: 600;\n      cursor: pointer;\n      transition: all 0.3s ease;\n      font-size: 14px;\n      box-shadow: var(--shadow);\n    }\n\n    .retry-button:hover {\n      transform: translateY(-2px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .retry-button:active {\n      transform: scale(0.95);\n    }\n\n    \/* 装饰元素 *\/\n    .decoration {\n      position: absolute;\n      z-index: 0;\n      pointer-events: none;\n    }\n\n    .decoration.circle {\n      width: 120px;\n      height: 120px;\n      border-radius: 50%;\n      background: rgba(107, 45, 216, 0.05);\n      top: 10%;\n      left: 10%;\n    }\n\n    .decoration.square {\n      width: 80px;\n      height: 80px;\n      transform: rotate(45deg);\n      background: rgba(78, 110, 242, 0.05);\n      bottom: 10%;\n      right: 10%;\n    }\n\n    \/* 响应式 *\/\n    @media (max-width: 768px) {\n      body {\n        padding: 12px;\n      }\n\n      .container {\n        max-width: 100%;\n        border-radius: 20px;\n      }\n\n      .header {\n        padding: 20px 15px;\n      }\n\n      .header h1 {\n        font-size: 1.3rem;\n      }\n\n      .header-icon {\n        font-size: 40px;\n      }\n\n      .version-comparison {\n        flex-direction: row;\n        flex-wrap: nowrap;\n        gap: 10px;\n        padding: 12px;\n        margin-top: 6px;\n        overflow-x: auto;\n      }\n\n      .version-card {\n        min-width: 45%;\n        padding: 26px 12px 12px;\n      }\n\n      \/* 移动端减弱呼吸动效 *\/\n      .version-card.latest-version {\n        animation: gradientAnimation 6s ease infinite;\n      }\n\n      .version-status {\n        top: 5px;\n        right: 5px;\n        padding: 2px 5px;\n        font-size: 0.6rem;\n      }\n\n      .version-number {\n        font-size: 1.1rem;\n      }\n\n      .version-card.latest-version .version-number {\n        font-size: 1.2rem;\n      }\n\n      .update-header h2, .history-header h2 {\n        font-size: 0.9rem;\n      }\n\n      .button {\n        padding: 12px 24px;\n        font-size: 0.95rem;\n      }\n\n      .history-content.expanded {\n        max-height: 50vh;\n        -webkit-overflow-scrolling: touch;\n      }\n    }\n\n    @media (max-width: 380px) {\n      .header h1 {\n        font-size: 1.2rem;\n      }\n\n      .version-number {\n        font-size: 1rem;\n      }\n\n      .version-card.latest-version .version-number {\n        font-size: 1.1rem;\n      }\n\n      .button {\n        padding: 11px;\n        font-size: 0.9rem;\n      }\n    }\n  <\/style>\n<\/head>\n<body>\n  <div class=\"decoration circle\"><\/div>\n  <div class=\"decoration square\"><\/div>\n\n  <div id=\"loading\" class=\"loading-wrapper\">\n    <div class=\"loading-spinner\"><\/div>\n    <div class=\"loading-text\"><i class=\"fas fa-search\"><\/i> 正在检查更新...<\/div>\n  <\/div>\n\n  <div class=\"container\" id=\"container\">\n    <div class=\"header\">\n      <div class=\"header-icon\"><i class=\"fas fa-book\"><\/i><\/div>\n      <h1>晴天书源更新<\/h1>\n      <p>请使用阅读测试版,不支持正式版<\/p>\n    <\/div>\n\n    <div class=\"version-comparison\">\n      <div class=\"version-card current-version\">\n        <div class=\"version-status status-outdated\" id=\"currentStatus\">待检查<\/div>\n        <h3><i class=\"fas fa-cube\"><\/i> 当前版本<\/h3>\n        <div class=\"version-number\" id=\"currentVersion\">-<\/div>\n        <div class=\"version-date\">您的当前版本<\/div>\n      <\/div>\n\n      <div class=\"version-indicator update-needed\" id=\"versionIndicator\" style=\"display: none;\">\n        <i class=\"fas fa-arrow-right\"><\/i>\n      <\/div>\n\n      <div class=\"version-card latest-version\">\n        <div class=\"version-status status-latest\" id=\"latestStatus\">最新版本<\/div>\n        <h3><i class=\"fas fa-star\"><\/i> 最新版本<\/h3>\n        <div class=\"version-number\" id=\"latestVersion\">-<\/div>\n        <div class=\"version-date\">可用最新版本<\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"content-container\">\n      <div class=\"status-alert\" id=\"statusAlert\" style=\"display: none;\"><\/div>\n\n      <div id=\"latestLogContainer\" style=\"display: none;\">\n        <div class=\"update-container\">\n          <div class=\"update-header\">\n            <h2><i class=\"fas fa-bolt\"><\/i> 最新更新<\/h2>\n            <div class=\"update-tag\">最新发布<\/div>\n          <\/div>\n          <div class=\"update-content\">\n            <div class=\"update-date\" id=\"latestLogDate\"><\/div>\n            <div class=\"update-text\" id=\"latestLogContent\"><\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"button-group\" id=\"buttonGroup\" style=\"display: none;\"><\/div>\n\n      <div class=\"history-container\" id=\"logs\" style=\"display: none;\">\n        <div class=\"history-header\" onclick=\"toggleLogs()\">\n          <h2><i class=\"fas fa-history\"><\/i> 历史更新 <span id=\"historyCount\"><\/span><\/h2>\n          <button class=\"toggle-history\" id=\"toggleButton\">\n            <span id=\"toggleText\">展开历史<\/span>\n            <i class=\"fas fa-chevron-down\" id=\"toggleIcon\"><\/i>\n          <\/button>\n        <\/div>\n        <div class=\"history-content\" id=\"logList\"><\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <script>\n  let logsCollapsed = true;\n\n  function toggleLogs() {\n    logsCollapsed = !logsCollapsed;\n    const logList = document.getElementById('logList');\n    const toggleText = document.getElementById('toggleText');\n    const toggleIcon = document.getElementById('toggleIcon');\n    \n    if (logsCollapsed) {\n      logList.classList.remove('expanded');\n      toggleText.textContent = '展开历史';\n      toggleIcon.className = 'fas fa-chevron-down';\n    } else {\n      logList.classList.add('expanded');\n      toggleText.textContent = '收起历史';\n      toggleIcon.className = 'fas fa-chevron-up';\n    }\n  }\n\n  (async function() {\n    const loading = document.getElementById('loading');\n    const container = document.getElementById('container');\n    const currentVersion = document.getElementById('currentVersion');\n    const latestVersion = document.getElementById('latestVersion');\n    const currentStatus = document.getElementById('currentStatus');\n    const latestStatus = document.getElementById('latestStatus');\n    const versionIndicator = document.getElementById('versionIndicator');\n    const statusAlert = document.getElementById('statusAlert');\n    const buttonGroup = document.getElementById('buttonGroup');\n    const latestLogContainer = document.getElementById('latestLogContainer');\n    const latestLogDate = document.getElementById('latestLogDate');\n    const latestLogContent = document.getElementById('latestLogContent');\n    const logsContainer = document.getElementById('logs');\n    const logList = document.getElementById('logList');\n    const historyCount = document.getElementById('historyCount');\n\n    const localVer = '${String(localVersion)}';\n\n    \/\/ 统一的服务器配置 - 方便维护\n    const serverConfig = {\n      main: {\n        name: '主线路',\n        icon: 'rocket',\n        baseUrl: 'https:\/\/sy.gyks.cf',\n        downloadPath: '\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup1: {\n        name: '备用线路1',\n        icon: 'box',\n        baseUrl: 'http:\/\/v1.gyks.cf',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup2: {\n        name: '备用线路2',\n        icon: 'satellite',\n        baseUrl: 'http:\/\/v2.gyks.cf',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup3: {\n        name: '备用线路3',\n        icon: 'link',\n        baseUrl: 'http:\/\/v3.gyks.cf',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup4: {\n        name: '备用线路4',\n        icon: 'bolt',\n        baseUrl: 'http:\/\/v4.gyks.cf',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup5: {\n        name: '备用线路5',\n        icon: 'globe',\n        baseUrl: 'http:\/\/v5.gyks.cf',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      },\n      backup6: {\n        name: '备用线路6',\n        icon: 'broadcast-tower',\n        baseUrl: 'http:\/\/101.35.133.34:8888',\n        downloadPath: '\/sy\/download\/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E6%99%B4%E5%A4%A9%E8%9E%8D%E5%90%884.0(vip%E5%AE%8C%E5%85%A8%E7%89%88).json'\n      }\n    };\n\n    \/\/ 版本比较函数\n    function compareVersions(vs) {\n      const normalize = (v) => {\n        return v.split('.').map(n => {\n          const num = parseInt(n, 10);\n          return isNaN(num) ? 0 : num;\n        });\n      };\n\n      const parts1 = normalize(localVer);\n      const parts2 = normalize(vs);\n      const maxLength = Math.max(parts1.length, parts2.length);\n      \n      for (let i = 0; i < maxLength; i++) {\n        const num1 = parts1[i] || 0;\n        const num2 = parts2[i] || 0;\n        if (num1 > num2) return 1;\n        if (num1 < num2) return -1;\n      }\n      return 0;\n    }\n\n    async function fetchVersionData() {\n      \/\/ 使用统一配置中除主线路外的备用线路进行版本检查\n      const serversToCheck = Object.values(serverConfig).filter(s => s.baseUrl.includes('gyks.cf') || s.baseUrl.includes('101.35'));\n      \n      for (const server of serversToCheck) {\n        try {\n          const response = await fetch(server.baseUrl + '\/version', { timeout: 2000 });\n          if (response.ok) {\n            return await response.json();\n          }\n        } catch (e) {\n          console.warn(\\`接口失败:\\${server.baseUrl}\\`, e);\n        }\n      }\n      throw new Error('所有更新接口都请求失败');\n    }\n\n    function showError(message) {\n      loading.innerHTML = \\`\n        <div class=\"error-state\">\n          <div class=\"error-icon\"><i class=\"fas fa-exclamation-triangle\"><\/i><\/div>\n          <div class=\"error-text\">\\${message}<\/div>\n          <button class=\"retry-button\" onclick=\"location.reload()\"><i class=\"fas fa-redo\"><\/i> 重试<\/button>\n        <\/div>\n      \\`;\n    }\n\n    try {\n      const data = await fetchVersionData();\n      const cloudVersion = String(data.version3);\n      const updateLog = data.update_log || {};\n\n      \/\/ 显示版本信息\n      currentVersion.textContent = \\`v\\${localVer}\\`;\n      latestVersion.textContent = \\`v\\${cloudVersion}\\`;\n\n      \/\/ 处理日志\n      const logEntries = Object.entries(updateLog);\n      if (logEntries.length > 0) {\n        \/\/ 显示最新日志\n        const [latestDate, latestContent] = logEntries[0];\n        latestLogDate.innerHTML = \\`<i class=\"fas fa-calendar-alt\"><\/i> \\${latestDate}\\`;\n        latestLogContent.textContent = latestContent;\n        latestLogContainer.style.display = 'block';\n\n        \/\/ 显示历史日志\n        if (logEntries.length > 1) {\n          const historyLogs = logEntries.slice(1);\n          historyCount.textContent = \\`(\\${historyLogs.length}条)\\`;\n          logList.innerHTML = historyLogs.map(([date, content]) => \\`\n            <div class=\"history-item\">\n              <div class=\"history-date\">\n                <i class=\"fas fa-calendar-day\"><\/i>\n                <span>\\${date}<\/span>\n              <\/div>\n              <div class=\"history-text\">\\${content}<\/div>\n            <\/div>\n          \\`).join('');\n          logsContainer.style.display = 'block';\n        }\n      }\n\n      \/\/ 检查更新状态\n      const compareResult = compareVersions(cloudVersion);\n      \n      \/\/ 显示版本指示器\n      versionIndicator.style.display = 'flex';\n      \n      if (compareResult === -1) {\n        \/\/ 需要更新\n        currentStatus.textContent = '待更新';\n        currentStatus.className = 'version-status status-outdated';\n        versionIndicator.className = 'version-indicator update-needed';\n        versionIndicator.innerHTML = '<i class=\"fas fa-arrow-right\"><\/i>';\n\n        \/\/ 使用统一配置生成下载按钮\n        buttonGroup.innerHTML = Object.values(serverConfig).map(server => {\n          const fullUrl = server.baseUrl + server.downloadPath;\n          return \\`\n            <a href=\"yuedu:\/\/booksource\/importonline?src=\\${encodeURIComponent(fullUrl)}\" class=\"button\">\n              <i class=\"fas fa-\\${server.icon}\"><\/i>\n              <span>\\${server.name}<\/span>\n            <\/a>\n          \\`;\n        }).join('');\n        buttonGroup.style.display = 'flex';\n      } else {\n        \/\/ 已是最新版本\n        currentStatus.textContent = '最新';\n        currentStatus.className = 'version-status status-latest';\n        versionIndicator.className = 'version-indicator is-latest';\n        versionIndicator.innerHTML = '<i class=\"fas fa-check\"><\/i>';\n        \n        statusAlert.className = 'status-alert up-to-date';\n        statusAlert.innerHTML = '<i class=\"fas fa-check-circle\"><\/i> <div>您已是最新版本<\/div>';\n        statusAlert.style.display = 'flex';\n      }\n\n      \/\/ 显示主容器,隐藏加载\n      loading.style.display = 'none';\n      container.style.display = 'block';\n\n    } catch (err) {\n      console.error('版本检查失败:', err);\n      showError('<i class=\"fas fa-exclamation-circle\"><\/i> 检查更新失败,请稍后重试<br><small>' + err.message + '<\/small>');\n    }\n  })();\n  <\/script>\n<\/body>\n<\/html>\n`;\n    java.startBrowser(`data:text\/html;base64,${java.base64Encode(html)}`, '晴天书源更新');\n}",
    "respondTime": 180000,
    "ruleBookInfo": {
        "author": "$.author",
        "canReName": "1",
        "coverUrl": "$.thumb_url",
        "init": "<js>\nif (String(baseUrl).startsWith(\"data:\")) {\n    let res = JSON.parse(java.hexDecodeToString(result));\n    let book_id = res.book_id;\n    let tab = res.tab;\n    let sources = res.sources;\n    let url = res.url;\n    let html = \"\";\n    let proxy = getArguments(source.getVariable(), \"proxy\");\n    if (url != \"\" && proxy == \"本地\") {\n        if (sources == '69书吧') {\n            let ck69 = String(cookie.getCookie(url));\n            let headers = {\n                \"Cookie\": ck69\n            };\n            let op = JSON.stringify({\n                \"headers\": headers\n            });\n            html = java.ajax(url + ',' + op);\n        } else {\n            html = java.ajax(url);\n        }\n        \/\/java.log(html);\n        if (html.includes(\"Just a moment...\") && sources == '69书吧') {\n            cookie.removeCookie(url);\n            var x = `https:\/\/www.69shuba.com`;\n            java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n            var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n            let ck69 = String(cookie.getCookie(url));\n            let headers = {\n                \"Cookie\": ck69\n            };\n            let op = JSON.stringify({\n                \"headers\": headers\n            });\n            java.log(op);\n            html = java.ajax(url + ',' + op);\n            \/\/java.log(html);\n        }\n    }\n    let base_url = getArguments(source.getVariable(), \"server\");\n    let op = {\n        method: \"POST\",\n        body: {\n            html: html\n        }\n    };\n    op = JSON.stringify(op);\n    let varia = String(book.getVariable('custom'));\n    if (varia == 'null') {\n        varia = '';\n    }\n    varia = JSON.stringify({\n        'custom': varia\n    });\n    \/\/varia = java.base64Encode(varia);\n    java.log(`${base_url}\/detail?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\n    result = java.ajax(`${base_url}\/detail?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\n}\nresult\n<\/js>$.data",
        "intro": "<js>\nlet {\n    book_id,\n    source: sources,\n    tab,\n    book_tts,\n    tags,\n    role,\n    last_chapter_title,\n    last_chapter_update_time,\n    word_number,\n    status,\n    score,\n    abstract,\n    copyright_info\n} = result;\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (proxy == \"本地\") {\n    proxy = \"本地网络\";\n} else {\n    proxy = \"服务器网络\";\n}\njava.put(\"book_detail\", JSON.stringify(result));\n\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet key = \"\";\ntry {\n    let cookieValue =\n        String(cookie.getCookie(base_url)) || String(java.getCookie(base_url));\n    key = getKey(cookieValue);\n} catch (e) {\n    key = \"\";\n}\n\nif (key == \"\") {\n    java.log(\"当前服务器未查询到登录状态,尝试查询其他服务器登录状态...\");\n    let cookieValue;\n    for (let h of host) {\n        try {\n            cookieValue = String(cookie.getCookie(h)) || String(java.getCookie(h));\n            key = getKey(cookieValue);\n        } catch (e) {\n            key = \"\";\n        }\n        if (key) {\n            java.log(`已在${h}登录,退出查询,正在转移登录状态到当前服务${base_url}`);\n            \/\/java.log(cookieValue)\n            removeCookie(h);\n            removeCookie(base_url);\n            cookie.setCookie(base_url, cookieValue);\n            break;\n        }\n    }\n}\n\nif (book.readConfig == null || book.readConfig.useReplaceRule == null) {\n    book.setUseReplaceRule(false);\n}\n\nlet nickname = '账号状态:⚠️ 未登录 | 点击右上角 🔖 登录';\ntry {\n    let opcx = {\n        method: \"GET\",\n        headers: {\n            cookie: 'qttoken=' + key + ';'\n        },\n    };\n    opcx = JSON.stringify(opcx);\n    let user_info = JSON.parse(java.ajax(base_url + '\/get_avatar,' + opcx));\n    if (user_info.code == 0) {\n        if (user_info.nickname) {\n            nickname = '欢迎回来:' + user_info.nickname\n        } else {\n            nickname = '欢迎回来:' + user_info.email + \"(请前往用户后台设置用户名)\"\n        }\n    }\n} catch (e) {\n    if (key) {\n        nickname = '账号状态:已登录'\n    }\n};\n\nlet loginStatus = nickname;\n\nlet lightDivider = \"❇️───────❇️───────❇️\";\nlet heavyDivider = \"&lrm;\\n&lrm;\";\n\nlet isValid = (value) => String(value).length > 1;\n\nlet info = `\n    📡 当前服务:${base_url}\n    🔑 ${loginStatus}\n    🏷 数据来源:${sources}\n    🔄 当前模式:${tab}\n    ⚙️ 访问模式:${proxy}\n`;\n\nif (tab == \"听书\") {\n    let toneId = getArguments(source.getVariable(), \"tone_id\");\n    if (isValid(book_tts)) {\n        info += `${lightDivider}\n    🎵 音色配置:${toneId}\n    ${book_tts}\n`;\n    }\n}\n\nlet basicInfo = \"\";\nlet addBasicInfo = (value, prefix, icon) => {\n    if (isValid(value)) basicInfo += `    ${icon} ${prefix} ${value}\\n`;\n};\n\naddBasicInfo(tags, \"书籍分类:\", \"🌈\");\naddBasicInfo(role, \"书籍主角:\", \"👑\");\naddBasicInfo(last_chapter_title, \"最新章节:\", \"📚\");\naddBasicInfo(last_chapter_update_time, \"更新时间:\", \"⏳\");\naddBasicInfo(word_number, \"书籍字数:\", \"📊\");\naddBasicInfo(status, \"书籍状态:\", \"🚩\");\naddBasicInfo(score, \"书籍评分:\", \"⭐\");\n\nif (basicInfo) info += `${lightDivider}\\n${basicInfo}`;\n\nif (isValid(abstract)) {\n    let indentedAbstract = abstract\n        .split(\"\\n\")\n        .map((line) => `    ${line}`)\n        .join(\"\\n\");\n    info += `${heavyDivider}\n    📖 书籍简介:\n${indentedAbstract}\n`;\n} else {\n    info += `${heavyDivider}`;\n}\n\nif (isValid(copyright_info)) {\n    info += `${lightDivider}\n    © ${copyright_info}\n`;\n} else {\n    info += `${lightDivider}`;\n}\n\ninfo += `\n${heavyDivider}\n    💠💠💠 数据更新于 ${new Date().toLocaleString()} 💠💠💠\n`;\nlet jjinfo = getArguments(source.getVariable(), \"info\");\n\nif (jjinfo != \"on\") {\n    info = String(info)\n        .split(\"\\n\")\n        .map((line) => line.replace(\/^ {4}\/, \"\"))\n        .join(\"\\n\");\n} else {\n    basicInfo = \"\";\n    addBasicInfo(last_chapter_title, \"最新章节:\", \"📚\");\n    addBasicInfo(last_chapter_update_time, \"更新时间:\", \"⏳\");\n    addBasicInfo(word_number, \"书籍字数:\", \"📊\");\n    addBasicInfo(status, \"书籍状态:\", \"🚩\");\n    addBasicInfo(score, \"书籍评分:\", \"⭐\");\n    if (isValid(abstract)) {\n        let indentedAbstract = abstract\n            .split(\"\\n\")\n            .map((line) => `    ${line}`)\n            .join(\"\\n\");\n        basicInfo += `\n    \\n&lrm;\n    📖 书籍简介:\n${indentedAbstract}\n`;\n    } else {\n        basicInfo += `${heavyDivider}`;\n    }\n    info = `&lrm;\\n🏷 数据来源:${sources}\\n` + basicInfo;\n}\n<\/js>",
        "lastChapter": "{{$.source}} {{$.last_chapter_title}} {{$.last_chapter_update_time}}",
        "name": "$.book_name",
        "tocUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || \"小说\";\nlet url = result.toc_url || \"\";\nvar sdtoken;\ntry {\n    var loginInfoMap = source.getLoginInfoMap ? source.getLoginInfoMap() : {};\n    sdtoken = String(loginInfoMap['手动填写番茄token(可不填)'] || '');\n} catch (e) {\n    sdtoken = '';\n}\nvar rawCookie = getFanqieCookie() || sdtoken;\nvar match = rawCookie.match(\/sessionid=[^;]+\/);\nvar fqcookie = match ? match[0] : '';\nvar fqssionid = '';\nif (fqcookie) {\n    fqssionid = getSessionId(fqcookie);\n};\nsetArguments('fqssionid', fqssionid);\njava.put(\"tab\", tab);\njava.put(\"book_id\", book_id);\nlet qtcatalog = {\n    book_id: book_id,\n    sources: sources,\n    tab: tab,\n    url: url,\n};\nqtcatalog = java.base64Encode(JSON.stringify(qtcatalog));\n`data:;base64,${qtcatalog},{\"type\":\"qingtian2\"}`;\n<\/js>",
        "wordCount": "$.word_number"
    },
    "ruleContent": {
        "content": "<js>\nresult = String(java.hexDecodeToString(result));\nlet res;\nif (result.match(\/晴天融合\/)) {\n    result = result.split(\"晴天融合4\");\n    res = {\n        item_id: result[0],\n        tab: result[1],\n        title: result[2],\n        sources: result[3],\n        url: \"\"\n    };\n} else {\n    res = JSON.parse(result);\n}\nlet varia = String(book.getVariable('custom'));\nif (varia == 'null') {\n    varia = '';\n}\nvaria = JSON.stringify({\n    'custom': varia\n});\n\/\/  varia = java.base64Encode(varia);\nlet book_id = res.book_id;\nlet item_id = res.item_id;\nlet tab = res.tab;\nlet title = res.title;\nlet sources = res.sources;\nlet url = res.url;\nlet html = \"\";\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (url != \"\" && proxy == \"本地\") {\n    if (sources == '69书吧') {\n        let ck69 = String(cookie.getCookie(url));\n        let headers = {\n            \"Cookie\": ck69,\n            \"User-Agent\": \"Mozilla\/5.0 (Linux; Android 6.0; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Mobile Safari\/537.36 Edg\/138.0.0.0\"\n        };\n        let op = JSON.stringify({\n            \"headers\": headers\n        });\n        java.log(url);\n        java.log(op);\n        html = java.ajax(url + ',' + op);\n    } else {\n        html = java.ajax(url);\n    }\n    java.log(html);\n    if (html.includes(\"Just a moment...\") && sources == '69书吧' && book.durChapterIndex === chapter.index) {\n        cookie.removeCookie(url);\n        var x = url;\n        java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n        var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n        let ck69 = String(cookie.getCookie(url));\n        let headers = {\n            \"User-Agent\": \"Mozilla\/5.0 (Linux; Android 6.0; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Mobile Safari\/537.36 Edg\/138.0.0.0\",\n            \"Cookie\": ck69\n        };\n        let op = JSON.stringify({\n            \"headers\": headers\n        });\n        java.log(op);\n        html = java.ajax(url + ',' + op);\n        \/\/java.log(html);\n    }\n};\nlet content = \"\";\nlet data;\nlet tone_id = getArguments(source.getVariable(), \"tone_id\");\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet device, device_type;\ntry {\n    device = java.androidId();\n    device_type = \"安卓\";\n} catch (e) {\n    try {\n        device = java.deviceID();\n        device_type = \"苹果\";\n    } catch (e) {\n        device = \"\";\n        device_type = \"安卓\";\n    }\n}\n\nlet qtcookie = cookie.getCookie(base_url);\ntry {\n    qtcookie = `qttoken=${String(cookie.getKey(base_url, \"qttoken\"))}; deviceId=${device};`\n} catch (e) {}\n\nvar params = {\n    html: html,\n    item_id: item_id,\n    source: sources,\n    tab: tab,\n    tone_id: tone_id,\n    variable: varia,\n    version: '4.11.5.1'\n};\n\nvar content_url = '\/content';\n\nif ((sources == \"番茄\" || sources == \"七猫\") && getArguments(source.getVariable(), \"fqpara\") == \"on\" && tab == \"小说\") {\n    content_url = '\/content?review=1';\n}\n\n\/\/var signInfo = generateComplexSignature('POST', content_url, {}, APP_SECRET, params);\n\n\n\/\/var signedParams = copyObject(params);\n\/\/signedParams.timestamp = signInfo.timestamp;\n\/\/signedParams.nonce = signInfo.nonce;\n\/\/signedParams.sign = signInfo.sign;\n\n\nvar op = {\n    method: \"POST\",\n    body: JSON.stringify(params),\n    headers: {\n        cookie: qtcookie,\n        'Content-Type': 'application\/json'\n    }\n};\n\nop = JSON.stringify(op);\njava.log(op);\ndata = java.ajax(base_url + content_url + `,${op}`);\n\ntry {\n    data = JSON.parse(data);\n    if (data.msg) {\n        java.toast(data.msg);\n    }\n} catch (e) {}\n\ncontent = data.content\n\nif ((sources == \"番茄\" || sources == \"七猫\") && getArguments(source.getVariable(), \"fqpara\") == \"on\" && tab == \"小说\") {\n    var fqssionid = getArguments(source.getVariable(), \"fqssionid\") || \"\";\n    content = content\n        .replace(\/ident=\"\/g, 'ident=\"' + base_url)\n        .replace(\/book_id=\/g, 'book_id=' + book_id + '&ssionid=' + fqssionid);\n    if (device_type == \"苹果\") {\n        content = paraForiOS(content, sources);\n    } else {\n        content = paraForAndroid(content, sources);\n    }\n\n\n}\ndata = JSON.stringify({\n    content: content,\n});\n\nif (device_type == \"安卓\" && (tab == \"短剧\" || tab == \"视频\" || sources == '毒舌影视')) {\n    data = {\n        content: `【右上角刷新】开启播放(下一集请切换下一章刷新)\\n播放直链:\\n${content}`,\n    };\n    data = JSON.stringify(data);\n    if (book.durChapterIndex === chapter.index) {\n        let video_url = `${base_url}\/online_video?book_id=${book_id}&source=${sources}&tab=${tab}`;\n        if (sources == '毒舌影视') {\n            video_url = content;\n        };\n        java.startBrowser(video_url, title);\n        java.toast(\"正在加载视频...\");\n    }\n\n}\ndata;\n<\/js>$.content",
        "imageStyle": "TEXT"
    },
    "ruleExplore": {
        "author": "$.author",
        "bookList": "$.data",
        "bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet url = result.toc_url || '';\n\nlet qtdetail = {\n    book_id: book_id,\n    sources: sources,\n    tab: tab,\n    url: url\n}\nqtdetail = java.base64Encode(JSON.stringify(qtdetail));\n`data:;base64,${qtdetail},{\"type\":\"qingtian\"}`\n<\/js>",
        "coverUrl": "$.thumb_url",
        "intro": "$.abstract",
        "kind": "{{$.category}}\n{{$.score}}\n{{$.status}}\n{{$.source}}\n{{$.tags}}",
        "lastChapter": "{{$.last_chapter_title}} • {{$.last_update_time}}",
        "name": "$.book_name",
        "wordCount": "$.word_number"
    },
    "ruleSearch": {
        "author": "$.author",
        "bookList": "$.data",
        "bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet url = result.toc_url || '';\n\nlet qtdetail = {\n    book_id: book_id,\n    sources: sources,\n    tab: tab,\n    url: url\n}\nqtdetail = java.base64Encode(JSON.stringify(qtdetail));\n`data:;base64,${qtdetail},{\"type\":\"qingtian\"}`\n<\/js>",
        "checkKeyWord": "我的26岁女房客@番茄",
        "coverUrl": "$.thumb_url",
        "intro": "$.abstract",
        "kind": "{{$.status}},{{$.score}},{{$.tags}},{{$.last_chapter_update_time}}",
        "lastChapter": "{{$.source}} {{$.last_chapter_title}}",
        "name": "$.book_name##(别名:.*?)",
        "wordCount": "$.word_number"
    },
    "ruleToc": {
        "chapterList": "<js>\nlet res = JSON.parse(java.hexDecodeToString(result));\nif (res.method) {\n    res = Object.fromEntries(\n        res.body\n        .replace(\"source\", \"sources\")\n        .split(\"&\")\n        .map((query) => query.split(\"=\"))\n    );\n    res.url = \"\";\n}\nlet book_id = res.book_id;\njava.put('book_id', book_id);\nlet tab = res.tab;\nlet sources = res.sources;\nlet url = res.url;\nlet html = \"\";\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (url != \"\" && proxy == \"本地\") {\n    if (sources == '69书吧') {\n        let ck69 = String(cookie.getCookie(url));\n        let headers = {\n            \"Cookie\": ck69\n        };\n        let op = JSON.stringify({\n            \"headers\": headers\n        });\n        html = java.ajax(url + ',' + op);\n    } else {\n        html = java.ajax(url);\n    }\n    \/\/java.log(html);\n    if (html.includes(\"Just a moment...\") && sources == '69书吧') {\n        cookie.removeCookie(url);\n        var x = `https:\/\/www.69shuba.com`;\n        java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n        var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n        let ck69 = String(cookie.getCookie(url));\n        let headers = {\n            \"Cookie\": ck69\n        };\n        let op = JSON.stringify({\n            \"headers\": headers\n        });\n        \/\/java.log(op);\n        html = java.ajax(url + ',' + op);\n        \/\/java.log(html);\n    }\n};\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet op = {\n    method: \"POST\",\n    body: {\n        html: html\n    }\n};\nop = JSON.stringify(op);\nlet varia = String(book.getVariable('custom'));\nif (varia == 'null') {\n    varia = '';\n}\nvaria = JSON.stringify({\n    'custom': varia\n});\n\/\/ varia = java.base64Encode(varia);\n\/\/java.log(`${base_url}\/catalog?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\nlet data = java.ajax(\n    `${base_url}\/catalog?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`\n);\nlet device;\nlet device_type;\ntry {\n    device = java.androidId();\n    device_type = \"安卓\";\n} catch (e) {\n    device_type = \"苹果\";\n}\n\nif (tab == \"小说\") {\n    if (device_type == \"安卓\") {\n        book.type = 8;\n    } else {\n        book.type = 0;\n    }\n} else if (tab == \"听书\") {\n    if (device_type == \"安卓\") {\n        book.type = 32;\n    } else {\n        book.type = 1;\n    }\n} else if (tab == \"漫画\") {\n    if (device_type == \"安卓\") {\n        book.type = 64;\n    } else {\n        book.type = 2;\n    }\n} else if (tab == \"短剧\") {\n    if (device_type == \"安卓\") {\n        book.type = 8;\n    } else {\n        book.type = 3;\n    }\n} else {\n    if (device_type == \"安卓\") {\n        book.type = 8;\n    } else {\n        book.type = 0;\n    }\n}\ndata;\n<\/js>$.data",
        "chapterName": "$.title",
        "chapterUrl": "<js>\nlet tab = result.tab;\nlet sources = result.source;\nlet title = result.title;\nlet item_id = result.item_id;\nlet book_id = java.get(\"book_id\");\nlet url = result.toc_url || \"\";\nlet qtcontent = {\n    book_id: book_id,\n    item_id: item_id,\n    title: title,\n    sources: sources,\n    tab: tab,\n    url: url,\n};\nqtcontent = java.base64Encode(JSON.stringify(qtcontent));\nif (sources == '卷') {\n    content_url = item_id\n} else if ((sources == \"番茄\" || sources == \"七猫\") && tab == \"小说\") {\n    var base_url = getArguments(source.getVariable(), \"server\") || \"\";\n    var fqssionid = getArguments(source.getVariable(), \"fqssionid\") || \"\";\n    let sourcess = sources.replace('svip_', '');\n    content_url = `data:;base64,${qtcontent},{\"type\":\"qingtian3\",\"js\":\"book ? result : '${base_url}\/get_review?book_id=${book_id}&item_id=${item_id}&ssionid=${fqssionid}&source=${sourcess}'\"}`;\n} else {\n    content_url = `data:;base64,${qtcontent},{\"type\":\"qingtian3\"}`;\n}\n<\/js>",
        "updateTime": "$.first_pass_time"
    },
    "searchUrl": "<js>\nlet base_url = getArguments(source.getVariable(), 'server');\nlet media;\nlet sources = getArguments(source.getVariable(), 'source');\nif (String(key).startsWith(\"m:\") || String(key).startsWith(\"m:\")) {\n    media = \"漫画\"\n    key = key.slice(2)\n} else if (String(key).startsWith(\"t:\") || String(key).startsWith(\"t:\")) {\n    media = \"听书\"\n    key = key.slice(2)\n} else if (String(key).startsWith(\"d:\") || String(key).startsWith(\"d:\")) {\n    media = \"短剧\"\n    key = key.slice(2)\n} else if (String(key).startsWith(\"x:\") || String(key).startsWith(\"x:\")) {\n    media = \"小说\"\n    key = key.slice(2)\n} else {\n    media = getArguments(source.getVariable(), 'media');\n}\nif (key.includes('@')) {\n    var parts = key.split('@');\n    key = parts[0];\n    sources = parts[1] || sources;\n}\nlet qtcookie = cookie.getCookie(base_url);\nlet op = {\n    method: \"GET\",\n    headers: {\n        cookie: qtcookie\n    },\n};\nop = JSON.stringify(op);\n`${base_url}\/search?title=${key}&tab=${media}&source=${sources}&page={{page}},${op}`\n<\/js>",
    "weight": 0
}
广告