📖 Lofter

Lofter

分享者: guaner001125 (317)发布时间: 2天前

点击标题可以将单篇文章加入书架

图片加载时有提示

二维码导入
{
    "articleStyle": 0,
    "cacheFirst": true,
    "customOrder": -10100160,
    "enableJs": true,
    "enabled": true,
    "enabledCookieJar": true,
    "header": "@js:\nJSON.stringify({\n\t \"User-Agent\":java.getWebViewUA(),\n\t\t\"Content-Type\": \"application\/x-www-form-urlencoded;charset=utf-8\",\n\t \"deviceid\": java.androidId(),\n\t \"if-modified-since\": String(new Date()).replace(\/(.*?)\\s(.*?)\\s(.*?)\\s(.*?)GMT.*\/,'$1, $3 $2 $4 GMT')\n})",
    "injectJs": "let imgEs = document.querySelectorAll(\".image-container\");\nif(imgEs.length > 0){\n    imgEs.forEach(container => {\n        container.onclick = (e) => {          \n            e.stopPropagation();                      \n            const img = container.querySelector('img');\n            if(img) {\n                const imgUrl = img.src+\",\"+JSON.stringify({\"headers\":{\"if-modified-since\":\"\"}});                \n                java.showPhoto(imgUrl);\n            }\n        };\n    });\n}",
    "jsLib": "const baseApi = \"https:\/\/api.lofter.com\";\nconst ver = \"product=lofter-android-8.3.20\";\nconst ver2 = \"product=lofter-android-7.4.4\";\nfunction S(e,s){\n\tconst {java} = this;\n\treturn String(java.getString(e,s??null))\n\t}\n\nfunction getCollectionSort(name,id,blogid){\n\treturn JSON.stringify({\n                [\"📖《\"+name+\"》倒序\"]:`${baseApi}\/v1.1\/postCollection.api?${ver2},{\"method\": \"POST\",\"body\":\"targetblogid=${blogid}&method=getCollectionSimple&offset={{(page-1)*50}}&limit=50&blogid=${blogid}&collectionid=${id}&order=0\"}`,\n                \"正序\":`${baseApi}\/v1.1\/postCollection.api?${ver2},{\"method\": \"POST\",\"body\":\"targetblogid=${blogid}&method=getCollectionSimple&offset={{(page-1)*50}}&limit=50&blogid=${blogid}&collectionid=${id}&order=1\"}`\n            })\n\t}\n\n\nfunction getUserSort(name,id){\n\treturn JSON.stringify({\n                [\"👤\"+name+\"的作品\"]:`${baseApi}\/v2.0\/blogHomePage.api?${ver},{\"method\":\"POST\",\"body\":\"targetblogid=${id}&supportposttypes=1%2C2%2C3%2C4%2C5%2C6&offset=0&method=getPostLists&postdigestnew=1&returnData=1&limit=18&checkpwd=1&needgetpoststat=1\"}`,\n                \"合集\":`${baseApi}\/v1.1\/postCollection.api?${ver},{\"method\":\"POST\",\"body\":\"targetblogid=${id}&method=getCollectionList&needViewCount=1&blogid=${id}\"}`,\n                \"粮单\":`${baseApi}\/api-grain\/grain\/list.json?offset=0&blogId=${id}`,\n                \"推荐\":`${baseApi}\/v1.1\/batchdata.api?${ver},{\"method\":\"POST\",\"body\":\"targetblogid=${id}&method=shares&offset=0&limit=18\"}`\n            })\n\t}\n\n\nfunction getSearchUrl(k,t){\n    const {java} = this;\t  \n    let baseUrl = baseApi+\"\/newsearch\/\";\n    let result = \"\";\n    \n    switch(t) {\n        \/\/用户\n    case 0:\n        result = baseUrl+'blog.json?key=' + k+ '&limit=10&offset=0';\n        break;\n        \n        \/\/合集\n    case 1:\n        result = baseUrl+'collection.json?key=' + k+ '&limit=20&offset=0';\n        break;\n        \n        \/\/粮单\n    case 2:\n        result = baseUrl+'grain.json?key='+ k +'&limit=10&offset=0'\n        break;\n        \n        \/\/文章\n    case 3:\n        result = baseUrl+'post.json?key=' + k + '&sortType=0&offset=0&limit=20'\n        break;\n        \/\/综合\n     default:\n        result = baseUrl+\"v2\/all.json?\"+ver+\"&sortType=0&limit=20&offset=0&version=1&key=\"+k\n        break;\n        }\n        \n        return result\n}\n\nfunction getSearchSort(searchText){\n    return JSON.stringify({\n                \"综合\":this.getSearchUrl(searchText),\n                \"文章\":this.getSearchUrl(searchText,3),\n                \"合集\":this.getSearchUrl(searchText,1),\n                \"用户\":this.getSearchUrl(searchText,0),\n                \"粮单\":this.getSearchUrl(searchText,2),\n            })\n}\n\nfunction getTagSort(id){\n    const {java} = this;\n   return JSON.stringify({\n                [\"🏷\"+id+\"的发现\"]:baseApi + \"\/recommend\/tagRecom.json?\"+ver+\"&offset=0&count=2&tag=\"+id+\"&source=\",\n                \"总榜\":`${baseApi}\/oldapi\/tagPosts.api?product=${ver2}&method=newTagSearch&offset=0&limit=22&firstpermalink=null&tag=${id}&type=total,{\"method\": \"POST\",\"body\":\"null\"}`,\n                \"日榜\":`${baseApi}\/oldapi\/tagPosts.api?${ver2}&method=newTagSearch&offset=0&limit=22&firstpermalink=null&tag=${id}&type=date,{\"method\": \"POST\",\"body\":\"null\"}`,\n                \"周榜\":`${baseApi}\/oldapi\/tagPosts.api?${ver2}&method=newTagSearch&offset=0&limit=22&firstpermalink=null&tag=${id}&type=week,{\"method\": \"POST\",\"body\":\"null\"}`,\n                \"月榜\":`${baseApi}\/oldapi\/tagPosts.api?${ver2}&method=newTagSearch&offset=0&limit=22&firstpermalink=null&tag=${id}&type=month,{\"method\": \"POST\",\"body\":\"null\"}`,\n                \"合集\":baseApi+\"\/newapi\/postCollection\/tagPage.json?offset=0&tag=\"+id,\n                \"作者\":`${baseApi}\/v1.1\/batchdata.api?${ver},{\"method\": \"POST\",\"body\":\"method=exploreblogs&offset=0&limit=20&tag=${id}&type=tag\"}`,\n                \"💬图\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&lastposttime={\\{Date.now()}}&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=newComment&postTypes=2&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"💬文\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&lastposttime={\\{Date.now()}}&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=newComment&postTypes=1&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"💬视频\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&lastposttime={\\{Date.now()}}&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=newComment&postTypes=4&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"💬最新评论\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=newComment&postTypes=&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"🆕最新发布\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=new&postTypes=&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"🆕图\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=new&postTypes=2&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"🆕文\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=new&postTypes=1&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"🆕视频\":`${baseApi}\/newapi\/tagPosts.json,{\"method\": \"POST\",\"body\":\"abFlag=old&${ver}&offset=0&postYm=&returnGiftCombination=&range=0&firstpermalink=null&type=new&postTypes=4&postYmdEt=0&recentDay=0&protectedFlag=1&style=0&postYmdSt=0&tag=${id}\"}`,\n                \"🔎搜索\":`{\\{let a=\"\";svg=String(java.base64Encode(\\`<svg width=\"1190\" height=\"300\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"\/><text x=\"220\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"90\" fill=\"#333\" font-weight=\"bold\">输入要搜索的内容<\/text><text x=\"30\" y=\"200\" font-family=\"Arial, sans-serif\" font-size=\"50\" fill=\"#333\">下拉【🔍搜索】或刷新【🔍搜索】分类弹出输入框<\/text><\/svg>\\`));try{a=java.getVerificationCode('data:image\/svg+xml;base64,'+svg);}catch(e){};source.put(\"keyword\",a)}}`,\n                \"搜索文章\":`${baseApi}\/newsearch\/tag\/post2.json?tag=${id}&key={\\{source.get(\"keyword\")}}&excludeKey=&postTypes=&postYm=&offset=0`,\n                \"搜索合集\":`${baseApi}\/newsearch\/tag\/collection.json?tag=${id}&key={\\{source.get(\"keyword\")}}&excludeKey=&postTypes=&postYm=&offset=0`,\n                \"搜索粮单\":`${baseApi}\/newsearch\/tag\/grain.json?tag=${id}&key={\\{source.get(\"keyword\")}}&excludeKey=&postTypes=&postYm=&offset=0`,\n            });\n}\n\nfunction isL(){\n\tconst {source} = this;\n\ttry{\n\t\tsource.refreshJSLib();\n\t\treturn true\n\t\t}catch(e){\n\t\t\treturn false\n\t\t\t}\n\t}\n\nfunction getHtmlto(name,info,cover,type,url,id){\n    let yurl = url;\n    if(type==\"👤\")url=`http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-8.3.20,{\"method\": \"POST\",\"body\":\"targetblogid=${id}&method=getBlogInfoDetail&returnData=1&checkpwd=1&needgetpoststat=1\"}`;\nlet addUrl =  `legado:\/\/import\/addToBookshelf?src=${encodeURIComponent(url)},{\"origin\":\"📖Lofter\"}`;\nlet c = `<button class=\"copy-btn\" onclick=\"handleSubscribe()\">\n                <span class=\"copy-icon\">👤<\/span>\n                <span class=\"copy-text\">订阅<\/span>\n            <\/button><button class=\"copy-btn\" onclick=\"toOpen()\">\n                <span class=\"copy-icon\">🔍<\/span>\n                <span class=\"copy-text\">查看<\/span>\n            <\/button>`;\t\nlet result = `\n    <title>${name}<\/title>\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <p><a href=\"legado:\/\/import\/bookSource?src=${encodeURI(\"http:\/\/www.yckceo.com\/yuedu\/shuyuan\/json\/id\/6873.json\")}\">导入lofter书源<\/a><\/p>\n    <div class=\"user-profile-card\">\n    <div class=\"user-header\">\n            <img src=\"${cover}\" class=\"user-avatar\">\n            <div class=\"user-meta\">\n                <h2 class=\"username\">${name}<\/h2>\n                <p class=\"user-bio\">${info}<\/p>\n            <\/div>\n        <\/div>\n        \n        <div class=\"copy-section\">\n            <div class=\"copy-content\" id=\"copyContent\">\n${type}${name}::${yurl}\n            <\/div>\n            <button class=\"copy-btn\" onclick=\"handleCopy()\">\n                <span class=\"copy-icon\">⎘<\/span>\n                <span class=\"copy-text\">一键复制后粘贴到分类URL<\/span>\n            <\/button>\n            ${this.isL()?'<div id=\"btns\">':\"\"}\n            <button class=\"copy-btn\" onclick=\"toAdd()\">\n                <span class=\"copy-icon\">📚<\/span>\n                <span class=\"copy-text\">加入<\/span>\n            <\/button>\n            ${this.isL()?c:\"\"}\n            ${this.isL()?'<\/div>':\"\"}\n            <div class=\"copy-feedback\" id=\"copyFeedback\"><\/div>\n        <\/div>\n        \n         \n    <\/div>\n\n    <style>\n    #btns{\n        display:flex;\n    }\n    \n        .user-profile-card{\n            max-width: 600px;\n            margin: 0 auto;\n            padding: 25px;\n            background: white;\n            border-radius: 12px;\n            box-shadow: 0 5px 15px rgba(0,0,0,0.08);\n            font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n        }\n      \n        .user-header {\n            display: flex;\n            align-items: flex-start;\n            margin-bottom: 20px;\n        padding: 15px;\n        background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);\n        border-radius: 10px;\n        box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n        }\n        \n        .user-avatar {\n            width: 70px;\n            height: 70px;\n            border-radius: 50%;\n            object-fit: cover;\n            border: 3px solid white;\n            box-shadow: 0 3px 10px rgba(0,0,0,0.1);\n        }\n        \n        .user-meta {\n            margin-left: 18px;\n            flex: 1;\n        }\n        \n        .username {\n            margin: 0 0 5px;\n            color: #333;\n            font-size: 20px;\n            font-weight: 600;\n        }\n        \n        .user-bio {\n            margin: 0;\n            color: #666;\n            font-size: 15px;\n            line-height: 1.5;\n        }\n        \n        .copy-section {\n            margin-top: 25px;\n        }\n        \n        .copy-content {\n            padding: 15px;\n            background: #f8f9fa;\n            border-radius: 8px;\n            border: 1px solid #eaeaea;\n            font-family: 'Courier New', monospace;\n            font-size: 14px;\n            line-height: 1.5;\n            word-break: break-all;\n            white-space: pre-wrap;\n            margin-bottom: 15px;\n            max-height: 200px;\n            overflow-y: auto;\n        }\n        \n        .copy-btn {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            padding: 12px 24px;\n            margin:10px 0px;\n            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);\n            border: none;\n            border-radius: 8px;\n            font-size: 15px;\n            font-weight: 500;\n            cursor: pointer;\n            transition: all 0.3s;\n            width: 100%;\n            box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n        }\n        \n        .copy-btn:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 5px 10px rgba(0,0,0,0.15);\n        }\n        \n        .copy-icon {\n            font-size: 18px;\n            margin-right: 8px;\n        }\n        \n            #btns button{\n                padding:5px 5px;\n                margin:8px\n            }\n        \n        .copy-feedback {\n            height: 20px;\n            margin-top: 12px;\n            text-align: center;\n            font-size: 14px;\n            transition: all 0.3s;\n        }\n        \n        @media (max-width: 600px) {\n            .user-profile-card {\n                padding: 18px;\n                border-radius: 0;\n            }\n            \n            .user-header {\n                flex-direction: column;\n                align-items: center;\n                text-align: center;\n            }\n            \n            .user-meta {\n                margin-left: 0;\n                margin-top: 15px;\n            }\n            \n            .copy-content {\n                font-size: 13px;\n                padding: 12px;\n            }\n        }\n    <\/style>\n\n    <script>\n         const feedback = document.getElementById('copyFeedback');\n         function toAdd(){\n             window.location.href = '${addUrl}';\n         }\n         function toOpen(){\n             if(\/📖\/.test(\"${type}\")){\n                  run(\\`getCollectionSort(\"${name}\",\"${yurl.match(\/collectionid=(\\d+)\/)?.[1]}\",\"${yurl.match(\/blogid=(\\d+)\/)?.[1]}\")\\`).then(r=>java.open(\"sort\",r));\n              }else if(\/👤\/.test(\"${type}\")){\n               run(\\`getUserSort(\"${name}\",\"${id}\")\\`).then(r=>java.open(\"sort\",r));\n            }else if(\/📗\/.test(\"${type}\")){\n                java.open(\"sort\", '${yurl}',\"${type}${name} ${info.match(\/^\\d+篇\/)?.[0]??''}\");\n            }\n        }\n         \n         function handleSubscribe() {\n            try {\n                let id = \"${id||yurl.match(\/(?:collectionid|grainId)=(\\d+)\/)[1]}\"\n                let u = {\n                    \"id\":id,\n                    \"name\":\"${name}\",\n                    \"desc\":\\`${info.replace(\/<hr>\/g,'')}\\`,\n                    \"avatar\":\"${cover}\"\n                   };\n                   \n                   if(\"${type}\"===\"📖\"){\n                       let blogid = \"${yurl.match(\/blogid=(\\d+)\/)?.[1]}\";\n                       u.blogid = blogid\n                   }\n                 let type = \"${type}\";\n                 if(type === \"👤\") type = \"users\";\n                 if(type === \"📖\") type = \"collections\";\n                 if(type === \"📗\") type = \"grains\";\n                 let s = String(source.getVariable());\n                 s = \/{\/.test(s)?s:\"\";\n                let jsonData = JSON.parse(s || '{\"users\":[],\"collections\":[],\"grains\":[],\"tags\":[]}');\n               \n                let existingUser = jsonData[type].find(user => String(user.id) === id);\n    if (!existingUser) {\n        jsonData[type].push(u);\n        source.putVariable(JSON.stringify(jsonData));\n        java.toast(\"订阅成功\");\n        feedback.textContent = '订阅成功!';\n    }else{\n        java.toast(\"订阅已存在\");\n        feedback.textContent = '订阅已存在!';\n    }\n                feedback.style.color = '#4CAF50';\n                setTimeout(() => feedback.textContent = '', 2000);\n            } catch(err) {\n                feedback.textContent = '订阅失败';\n                feedback.style.color = '#F44336';\n                setTimeout(() => feedback.textContent = '', 2000);\n            }\n        }\n        \n        function handleCopy() {\n            const content = document.getElementById('copyContent');\n            \n            \/\/ 创建范围并选择文本\n            const range = document.createRange();\n            range.selectNode(content);\n            window.getSelection().removeAllRanges();\n            window.getSelection().addRange(range);\n            \n            try {\n                \/\/ 执行复制命令\n                const successful = document.execCommand('copy');\n                if(successful) {\n                    feedback.textContent = '复制成功!';\n                    feedback.style.color = '#4CAF50';\n                } else {\n                    feedback.textContent = '复制失败,请手动选择文本';\n                    feedback.style.color = '#F44336';\n                }\n            } catch(err) {\n                feedback.textContent = '复制错误: ' + err;\n                feedback.style.color = '#F44336';\n            }\n            \n            \/\/ 清除选择\n            window.getSelection().removeAllRanges();\n            \n            \/\/ 3秒后隐藏反馈\n            setTimeout(() => {\n                feedback.textContent = '';\n            }, 3000);\n        }\n    <\/script>\n    `;\n\t\nreturn result\t\n\t\n\t\n\t}\n",
    "lastUpdateTime": 1775399685473,
    "loadWithBaseUrl": true,
    "loginUi": "<js>\nlet s = source.getVariable();\ns = \/{\/.test(s)?s:\"\";\nlet mockData = JSON.parse(s || '{\"users\":[],\"collections\":[],\"grains\":[],\"tags\":[]}');\nlet all = [{\n        \"name\": \"默认启动页\",\n        \"type\": \"button\",   \n        \"action\":`source.put(\"start\",\"\");java.toast(\"恢复默认启动页\");java.reLoginView()`,\n            \"viewName\":`\"\"==\"${source.get(\"start\")}\"?\"✅默认启动页\":\"默认启动页\"`,   \n        \"style\": {\n            \"layout_flexGrow\": 1,            \n            \"layout_flexBasisPercent\": 1          \n        }\n    }];\n\nlet users = mockData.users;\nlet collections = mockData.collections;\nlet grains = mockData.grains;\nlet tags = mockData.tags;\n\n\nif(users.length || collections.length || grains.length ||grains.length){\n\tall.push({\n        \"name\": \"↓选择启动页:打开时会跳转的分类URL↓\",\n        \"type\": \"button\",      \n        \"style\": {\n            \"layout_flexGrow\": 1,            \n            \"layout_flexBasisPercent\": 1          \n        }\n    },{\n        \"name\": \"不再显示启动页\",\n        \"type\": \"button\",   \n        \"action\":`source.get(\"isStart\")==\"1\"?source.put(\"isStart\",\"0\"):source.put(\"isStart\",\"1\");java.reLoginView()`,\n            \"viewName\":`\"1\"==\"${source.get(\"isStart\")}\"?\"✅不再显示启动页\":\"不再显示启动页\"`,   \n        \"style\": {\n            \"layout_flexGrow\": 1,            \n            \"layout_flexBasisPercent\": 1          \n        }\n    })\n\t\n\t}\n\nfunction putStart(list,type){\n\tif(list.length){\n\t\tall.push({\n        \"name\": type,\n        \"type\": \"text\",      \n        \"style\": {\n            \"layout_flexGrow\": 1,            \n            \"layout_flexBasisPercent\": 1          \n        }\n    });\n    \n    list.forEach(x=>{\n    \tall.push({\n            \"name\": type,\n            \"type\": \"button\",    \n            \"action\":`source.put(\"start\",\"${x.id??x}\");java.toast(\"启动页:${x.name??x}\");java.reLoginView()`,\n            \"viewName\":`\"${x.id??x}\"==\"${source.get(\"start\")}\"?\"✅${x.name??x}\":\"${x.name??x}\"`,\n            \"style\": {\n                \"layout_flexGrow\": 1,            \n                \"layout_flexBasisPercent\": 0.25     \n               }\n             })\n    \t})\n\t}\n}\n\nputStart(users,\"用户\")\nputStart(collections,\"合集\")\nputStart(grains,\"粮单\")\nputStart(tags,\"标签\")   \nJSON.stringify(all)\n<\/js>",
    "loginUrl": "function login(){}",
    "preload": false,
    "preloadJs": "window.java = java;\nwindow.source = source;\nwindow.run = run;",
    "ruleArticles": "<js>\nresult = result.replace(\/:null\/g,':\"\"').replace(\/,\\s*null\/g,'');\n\nlet a = JSON.parse(result);\na?.data && (a.data.topItem = (a.data.topItem&&a.data?.topItem?.itemType!==39) ? [a.data.topItem] : []);\na?.response && (a.response.topPost = a.response.topPost ? [a.response.topPost] : []);\nif(baseUrl.includes(\"ranklist.json\")){\n\tlet i = baseUrl.match(\/t=(\\d+)\/)?.[1];\n\ta = a.data.rankList[i];\n\t}\nresult = JSON.stringify(a);\n<\/js>\n$.data.topItem&&$.hotLists&&$.response.topPost&&$.response.items[*]&&$.response.posts[*]&&$.response.blogs[*]&&$.data.grains[*]&&$.data.posts[*]&&$.data.blogs[*]&&$.data.collections[*]&&$.data.grainList[*]&&$.response.collections[*]&&$.data.list[*]&&$.data.hot[*]&&$.data.recommend[*]<js>\na=result;\nbaseUrl.match(\/newsearch\/)?result=\"[{post:{title右上角三点,设置源变量确认搜索'}}]\":result=result;\n(source.getVariable()!=''||isL())?result=a:result=result;\n<\/js>\n$.[*]",
    "ruleContent": "<js>\nif(baseUrl.includes(\"data:hot\")){\n\tlet title = java.hexDecodeToString(result);\n\tif(baseUrl.includes(\"hotsearch\") || baseUrl.includes(\"hottag\")){\n\t\tresult = `<title>刷新【搜索${title}】<\/title><script>\n    setTimeout(function() {\n        url = ${baseUrl.includes(\"hotsearch\")?getSearchSort(title):getTagSort(title)};\n        java.open(\"sort\",JSON.stringify(url));\n        window.close()\n},8);<\/script>`;\n\t\t}\n}else if(\/^https?:\\\/\\\/(?!www\\.)[^\"]+\\.lofter\\.com$\/.test(baseUrl)){\n    result = result.match(\/window.__initialize_data__ =([\\s\\S]+?)<\\\/script>\/)?.[1] ?? \"\";    \n    if(result && result!==\" undefined\"){    \t\n    java.setContent(result);\n    let url = `http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\":\"POST\",\"body\":\"supportposttypes=1%2C2%2C3%2C4%2C5%2C6&targetblogid=${S('$..data.blogInfo.blogId')}&offset={\\{(page-1)*18}}&method=getPostLists&postdigestnew=1&returnData=1&limit=18&checkpwd=1&needgetpoststat=1\"}`;\n    let info = `${S('$..authName')}<hr>${S('$..selfIntro')}`;\n    result = getHtmlto(S(\"$..data.blogInfo.blogNickName\"),info,S(\"$..data.blogInfo.bigAvaImg\"),\"👤\",url,S('$..data.blogInfo.blogId'));\n    }else{\n    \t   result = src\n    \t}\n    \n}else if(baseUrl.includes(\"share?collectionId=\")){        \n    result = result.match(\/window.__initialize_data__ =([\\s\\S]+?)<\\\/script>\/)?.[1] ?? \"\";    \n    if(result && result!==\" undefined\"){    \t\n    java.setContent(result);\n    blogid = S('$.data.collection.blogId');\n    id = S('$.data.collection.id');\n    let curl = 'https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=' +blogid+'&method=getCollectionSimple&offset={\\{(page-1)*2000}}&limit=2000&blogid=' + blogid + '&collectionid=' + id + '&order=1\"}';\n     let info = `${S('$.data.collection.postCount')}篇🏷${S('$.data.collection.tags||$.data.collection.tagList')}<hr>${S('$.data.collection.description')}`\n     result = getHtmlto(S(\"$.data.collection.name\"),info,S(\"$.data.collection.coverUrl\"),\"📖\",curl)\n    }else{\n    \t   result = src\n    \t}\n}else{\n\nif(\/window.__initialize_data__\/.test(result)){\n\tresult = result.match(\/window.__initialize_data__ =([\\s\\S]+?)<\\\/script>\/)[1];\n\tjava.setContent(result);\n}\n\n\ncontent = S(\"$..content||$..caption\");\nlet postid =  S(\"$..response.posts[0].post.id||$..postData.postView.id\");\nlet blogid = S(\"$..blogInfo.blogId\")\nimgs = eval(S(\"$..photoLinks\"));\nlet tags = S(\"$..tag\");\n\nlet author = S(\"$..blogInfo.blogNickName\");\nauthoru = `http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=${blogid}&method=getBlogInfoDetail&returnData=1&limit=2000&offset=0&&checkpwd=1&needgetpoststat=1\"}`;\nauthorurl= `legado:\/\/import\/addToBookshelf?src=${encodeURIComponent(authoru)},{\"origin\":\"📖Lofter\"}`\n\nlet  postCollection =S(\"$..postCollection.name\"); \nlet postNum = postCollection?\"(\"+S(\"$..postCollection.postCount\")+\"篇)\":\"\";\npostCollectionu = `https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=${S(\"$..postCollection.blogId\")}&method=getCollectionSimple&offset=0&limit=500&blogid=${S(\"$..postCollection.blogId\")}&collectionid=${S(\"$..postCollection.id\")}&order=1\"}`;\n\npostCollectionurl= `legado:\/\/import\/addToBookshelf?src=${encodeURIComponent(postCollectionu)},{\"origin\":\"📖Lofter\"}`\n\npostCollection = postCollection?`<p style=\"text-align:center\"><a class=\"toBook\" onclick='toOpen(\"📖\",\"${postCollection}\",\\`${postCollectionu}\\`,1)'>📖合集:<\/a><a href='${postCollectionurl}'>${postCollection}<\/a><\/p>`:\"\";\n\nauthor = `<p style=\"text-align:center\"><a class=\"toAuthor\" onclick='toOpen(\"👤\",\"${author}\",\\`${authoru}\\`,1)'>👤作者:<\/a><a href='${authorurl}'>${author}<\/a><\/p>${postCollection}`;\n\ntags = tags?tags.split(\",\").map(x=>{\n    let url = `https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={\\{(page-1) *18}}&limit=18&firstpermalink=null&tag=${x}&type=new,{\"method\": \"POST\",\"body\":\"null\"}`;\n\treturn `<label class=\"tag\" onclick='toOpen(\"🏷\",\"${x}\",\\`${url}\\`,1)'>${x}<\/label>`\n\t}).join(\"\"):null;\ntags = tags?`<div>${tags}<\/div>`:\"\";\nlet embed,img_height,img_width,video_first_img\ntry{\nembed = S(\"$.response.posts[0].post.embed\")??\"{x:1}\";\nimg_height = S(\"$.img_height\", embed);\nimg_width = S(\"$.img_width\", embed);\nvideo_first_img = S(\"$.video_first_img\", embed);\n}catch(e){\n\t\/\/java.log(e)\n\t}\n\/\/ 获取视频URL\nlet videoUrl = \/video_down_url\\\\\":\\\\\"(.*?)\\\\\"\/.test(result) ? String(result).match(\/video_down_url\\\\\":\\\\\"(.*?)\\\\\"\/)[1] : \"\";\n\nvideo = videoUrl ? `<div style=\"display: flex; flex-direction: column; align-items: center; margin: 5px 0;\"> \n  \n  <div style=\"width: 100%; max-width: 100%; border: 2px solid #e0e0e0; border-radius: 8px; box-shadow: 0 8px 25px rgba(0,0,0,0.15); background: #000; overflow: hidden;\">\n    <video controls poster=\"${video_first_img}\" style=\"width: 100%; display: block;\">\n      <source src=\"${videoUrl}\" type=\"video\/mp4\">\n    <\/video>\n  <\/div>\n<\/div>\n` : \"\";\n\nvideoUrl = videoUrl?`<div style=\"width: 100%; max-width: 90%; word-break: break-all; background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 8px; padding: 12px 15px; font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; color: #495057;\">\n    视频链接:${videoUrl}\n  <\/div>`:\"\";\n\nimg = \"\";\nif(imgs) {\n    imgs.forEach(x => {\n        if(x) {\n            let picurl = x.orign.replace(\/%7C.*\/g, '');\n            img += `<div class=\"image-container\">\n                <div class=\"loading-spinner\">加载中...<\/div>\n                <img src=\"${picurl}\" loading=\"lazy\" \n                     onload=\"this.parentNode.querySelector('.loading-spinner').style.display='none'; this.classList.add('loaded')\" \n                     onerror=\"this.parentNode.querySelector('.loading-spinner').style.display='none'; this.classList.add('error')\">\n            <\/div>\\n`;\n        }\n    });\n}\n\n\ncontent = content\n.replace(\/<a href=\"(.*?\\.lofter.com\\\/post\\\/[^\"]+?|.*?\\.lofter.com\\\/.*?share\\?collectionId[^\"]+?)\"[^>]+?>([^<]+)<\\\/a>\/g,'<a onclick=\\'openContent(\"$1\")\\' href=\\'javascript:;\\'>$2<\/a>')\n.replace(\/<a href=\"(https?:\\\/\\\/(?!www\\.)[^\"]+\\.lofter\\.com)\"[^>]+?>([^<]+)<\\\/a>\/g,'<a onclick=\\'openContent(\"$1\")\\' href=\\'javascript:;\\'>$2<\/a>')\n.replace(\/<p[^>]*>\\s* * *<\\\/p>\/g, '')\n.replace(\/\\s{2,}\/g,'')\n.replace(\/title=\"\"[^>]+|style=\"[^\"]+\"\/g,'\/')\n.replace(\/<img([^>]+)\\\/?>\/g,'<div class=\"image-container\"><div class=\"loading-spinner\">加载中...<\/div><img$1 loading=\"lazy\" onload=\"this.parentNode.querySelector(\\'.loading-spinner\\').style.display=\\'none\\'; this.classList.add(\\'loaded\\')\" onerror=\"this.parentNode.querySelector(\\'.loading-spinner\\').style.display=\\'none\\'; this.classList.add(\\'error\\')\"><\/div>')\n.replace(\/<a loftermentionblogid=\"(\\d+)\" href=\"[^\"]+\".*?>@([^<]+)<\\\/a>\/g,`<a onclick='toOpen(\"👤\",\"$2\",\\`http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=$1&method=getBlogInfoDetail&returnData=1&checkpwd=1&needgetpoststat=1\"}\\`,1)' href='javascript:;'>@$2<\/a>`);\n\ncontent = content.replace(\/<p[^>]*>\/g, '<p>'); \/\/ 移除p标签中的所有属性\n\nlet openUrlButton = `<button onclick=\"openUrl(1)\" \n                            style=\"\n                                background: #6c757d;\n                                color: white;\n                                border: none;\n                                padding: 8px 16px;\n                                border-radius: 4px;\n                                font-size: 14px;\n                                cursor: pointer;\n                                flex: 1;\n                                min-width: calc(33.33% - 7px);\n                                transition: background 0.2s ease;\n                            \"\n                            onmouseover=\"this.style.background='#5a6268';\"\n                            onmouseout=\"this.style.background='#6c757d';\">\n                        打开\n                    <\/button>`;\nlet addButton= `<button onclick=\"openUrl(0)\" \n                            style=\"\n                                background: #6c757d;\n                                color: white;\n                                border: none;\n                                padding: 8px 16px;\n                                border-radius: 4px;\n                                font-size: 14px;\n                                cursor: pointer;\n                                flex: 1;\n                                min-width: calc(33.33% - 7px);\n                                transition: background 0.2s ease;\n                            \"\n                            onmouseover=\"this.style.background='#5a6268';\"\n                            onmouseout=\"this.style.background='#6c757d';\">\n                        加入书架\n                    <\/button>`;\nlet starButton =  `<button onclick=\"handleSubscribe()\" \n                            style=\"\n                                background: #2c3e50;\n                                color: white;\n                                border: none;\n                                padding: 8px 16px;\n                                border-radius: 4px;\n                                font-size: 14px;\n                                cursor: pointer;\n                                flex: 1;\n                                min-width: calc(33.33% - 7px);\n                                transition: background 0.2s ease;\n                            \"\n                            onmouseover=\"this.style.background='#34495e';\"\n                            onmouseout=\"this.style.background='#2c3e50';\">\n                        订阅\n                    <\/button>`;\nlet postButton = ` <button id=\"postButton\" onclick=\"openPost()\" \n                            style=\"\n                                background: #2c3e50;\n                                color: white;\n                                border: none;\n                                padding: 8px 16px;\n                                border-radius: 4px;\n                                font-size: 14px;\n                                cursor: pointer;\n                                flex: 1;\n                                min-width: calc(33.33% - 7px);\n                                transition: background 0.2s ease;\n                            \"\n                            onmouseover=\"this.style.background='#34495e';\"\n                            onmouseout=\"this.style.background='#2c3e50';\">\n                        合集列表\n                    <\/button>`\n\nresult = `\n<title>${S(\"$..title||$..content\").replace(\/<\\\/?([a-z]+)[^>]*>|\\s\/g,'')}<\/title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n${'<h3 class=\"title-card\" onclick=\"openUrl(2)\">'+(S(\"$..title\") || \"无题\")+'<\/h3>'+author+'<hr>'}\n\n<div id=\"modalOverlay\" style=\"position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1001; opacity: 0; visibility: hidden; transition: all 0.3s ease; padding: 0;\">\n    <div id=\"modalContainer\" style=\"background-color: white;margin:0; padding:0;border-radius: 16px; width: 90%; max-width: 400px; max-height: 85vh; overflow: hidden; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); transform: translateY(30px); transition: transform 0.3s ease;\">\n        <div style=\"padding: 4px 14px; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; background-color: white;\">\n            <div style=\"font-size: 1rem; font-weight: 700; color: #1a1a1a;\">合集列表<span id=\"postnum\"><\/span><\/div>\n            <button id=\"closeModalBtn\" style=\"background: none; border: none; font-size: 1.8rem; color: #999; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s;\" onmouseover=\"this.style.backgroundColor='#f5f5f5'; this.style.color='#666';\" onmouseout=\"this.style.backgroundColor='transparent'; this.style.color='#999';\">×<\/button>\n        <\/div>\n        <div style=\"padding: 0; overflow-y: auto; max-height: calc(85vh - 80px);\">\n            <div id=\"collectionList\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n<div class=\"post-container\">\n    <div class=\"post-content\">\n        ${content}\n    <\/div>\n    ${img}\n    ${video}\n    ${tags}\n<\/div>\n${videoUrl}\n    <div id=\"apiPopupOverlay\" \n         style=\"\n            display: none;\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: rgba(0, 0, 0, 0.6);\n            z-index: 1000;\n            justify-content: center;\n            align-items: center;\n         \" \n         onclick=\"closeApiPopup()\">\n        \n        <div id=\"apiPopup\" \n             style=\"\n                background: white;\n                border-radius: 8px;\n                padding: 0;\n                width: 90%;\n                max-width: 700px;\n                max-height: 80vh;\n                box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);\n                position: relative;\n                display: flex;\n                flex-direction: column;\n             \" \n             onclick=\"event.stopPropagation();\">\n            \n            <div style=\"\n                background: #f8f9fa;\n                padding: 20px;\n                border-bottom: 1px solid #e9ecef;\n                border-radius: 8px 8px 0 0;\n                display: flex;\n                justify-content: space-between;\n                align-items: center;\n            \">\n                <h3 style=\"margin: 0; font-size: 16px; font-weight: 600; color: #333;\">\n                    API接口信息\n                <\/h3>\n                <button onclick=\"closeApiPopup()\" \n                        style=\"\n                            background: none;\n                            border: none;\n                            color: #666;\n                            font-size: 24px;\n                            cursor: pointer;\n                            padding: 0;\n                            line-height: 1;\n                            width: 30px;\n                            height: 30px;\n                            display: flex;\n                            align-items: center;\n                            justify-content: center;\n                            border-radius: 4px;\n                        \"\n                        onmouseover=\"this.style.background='#e9ecef';\"\n                        onmouseout=\"this.style.background='transparent';\">\n                    &times;\n                <\/button>\n            <\/div>\n            \n            <div style=\"padding: 20px; flex: 1; overflow: auto;\">\n                <textarea id=\"apiTextArea\" \n                          readonly\n                          style=\"\n                            width: 100%;\n                            height: 150px;\n                            padding: 12px;\n                            border: 1px solid #ddd;\n                            border-radius: 4px;\n                            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n                            font-size: 13px;\n                            line-height: 1.5;\n                            color: #333;\n                            background: #fafafa;\n                            resize: none;\n                            outline: none;\n                            box-sizing: border-box;\n                          \"\n                          onfocus=\"this.select();\"><\/textarea>\n                \n                \n                <div style=\"display: flex; gap: 10px; margin-top: 20px; flex-wrap: wrap;\">\n                    <button onclick=\"selectAndCopy()\" \n                            style=\"\n                                background: #2c3e50;\n                                color: white;\n                                border: none;\n                                padding: 8px 16px;\n                                border-radius: 4px;\n                                font-size: 14px;\n                                cursor: pointer;\n                                flex: 1;\n                                min-width: calc(33.33% - 7px);\n                                transition: background 0.2s ease;\n                            \"\n                            onmouseover=\"this.style.background='#34495e';\"\n                            onmouseout=\"this.style.background='#2c3e50';\">\n                        复制\n                    <\/button>\n                    \n              ${isL()?openUrlButton:\"\"}\n              ${isL()?starButton:\"\"}\n              ${addButton}\n              ${postButton}\n\n            <\/div>\n                \n                <!-- 提示信息 -->\n                <div id=\"copySuccess\" \n                     style=\"\n                        display: none;\n                        background: #d4edda;\n                        border: 1px solid #c3e6cb;\n                        color: #155724;\n                        padding: 10px 15px;\n                        border-radius: 4px;\n                        margin-top: 15px;\n                        text-align: center;\n                        font-size: 13px;\n                     \">\n                    文本已复制到剪贴板\n                <\/div>\n                \n                <!-- 使用说明 -->\n                <div style=\"\n                    margin-top: 20px;\n                    padding: 12px;\n                    background: #f8f9fa;\n                    border-left: 4px solid #6c757d;\n                    border-radius: 4px;\n                    font-size: 13px;\n                    color: #495057;\n                \">\n                    <div style=\"font-weight: 600; margin-bottom: 5px;\">使用说明:<\/div>\n                    复制上述文本后,可粘贴到分类URL中使用\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n<script>\n\nfunction renderCollections(collectionsData) {\n    collectionsData = collectionsData.response.collections;\n    const collectionList = document.getElementById('collectionList');\n    document.querySelector(\"#postnum\").textContent = \"(\"+collectionsData.length+\"个)\";\n    collectionList.innerHTML = '';\n    collectionsData.forEach(collection => {\n        const collectionItem = document.createElement('div');\n        collectionItem.style.cssText = 'display: flex; padding: 8px 10px; border-bottom: 1px solid #f0f0f0; align-items: center; justify-content: center;';\n       collectionItem.setAttribute('data-id', collection.id);\n       collectionItem.className = \"collectionItem\";\n       collectionItem.innerHTML = \\`\n       <div style=\"width: 88px; height: 88px; flex-shrink: 0; border-radius: 8px; overflow: hidden; margin-right: 16px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\">\n           <img src=\"$\\{collection.coverUrl}\" style=\"width:100%;height:100%\">\n      <\/div>\n      <div class=\"name\" style=\"flex: 1; display: flex; flex-direction: column; justify-content: space-between; min-height: 88px;font-weight: 500;color:#10a37f;font-size: 0.9rem;\">$\\{collection.name}\n          <div style=\"font-size: 0.8rem; color: #666; line-height: 1.1; margin-bottom: 5px;\">$\\{collection.description}<\/div>\n          <div style=\"display: flex; justify-content: space-between; align-items: center;\">\n              <div style=\"font-size: 0.7rem; color: #999; display: flex; align-items: center;\">\n              $\\{collection.postCount}篇•$\\{collection.viewCount}浏览 <br>🏷$\\{collection.tags}\n              <\/div>\n          <\/div>\n       <\/div>\n\\`;\ncollectionList.appendChild(collectionItem);\n});\n\ndocument.querySelectorAll('.collectionItem').forEach(btn => {\n    btn.addEventListener('click', function() {\n        const id = this.getAttribute('data-id');\n        const textarea = document.getElementById('apiTextArea').value.split(\"::\");\n        let name = this.querySelector(\".name\").textContent;\n        n = name.split(\"\\\\n\")[0];\n        let url = textarea[1];\n        let targetblogid= url.match(\/blogid=(\\\\d+)\/)[1];\n        url =  \"https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-7.4.4,\";\n        let post = {\"method\": \"POST\",\"body\":\"targetblogid=\"+targetblogid+\"&method=getCollectionSimple&offset=0&limit=500&blogid=\"+targetblogid+\"&collectionid=\"+id+\"&order=1\"}\n        url +=JSON.stringify(post);\n        toOpen(\"📖\",n,url,1,\"(\"+name.match(\/(\\\\d+篇)•\/)[1]+\")\")\n      });\n});\n}\n\n\nfunction showModal() {\n    const modalOverlay = document.getElementById('modalOverlay');\n    const modalContainer = document.getElementById('modalContainer');\n    document.getElementById('apiPopupOverlay').style.zIndex = \"1000\";\n    modalOverlay.style.zIndex = \"9999\";\n    modalOverlay.style.opacity = '1';\n    modalOverlay.style.visibility = 'visible';\n    modalContainer.style.transform = 'translateY(0)';\n    document.body.style.overflow = 'hidden';\n}\n\nfunction hideModal() {\n    const modalOverlay = document.getElementById('modalOverlay');\n    const modalContainer = document.getElementById('modalContainer');\n    modalOverlay.style.opacity = '0';\n    modalOverlay.style.visibility = 'hidden';\n    modalContainer.style.transform = 'translateY(30px)';\n    document.body.style.overflow = 'auto';\n}\n\n\n   \ndocument.getElementById('modalOverlay').addEventListener('click', function(e) {\n    if (e.target === this) {\n        hideModal();\n    }\n});\n\n\/\/ 显示弹窗\nfunction openContent(url){\n     try{\n             java.open(\"rss\", url);\n        }catch(e){\n             window.open(url)\n        }\n}\n\nasync function openPost(){\n    const textarea = document.getElementById('apiTextArea').value.split(\"::\");\n    let url = textarea[1];\n    let targetblogid= url.match(\/blogid=(\\\\d+)\/)[1];\n    let postUrl = \"https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-8.3.20\";\n    let response,jsonData;\n    try{\n         response = java.ajax(postUrl+\",\"+JSON.stringify({\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application\/x-www-form-urlencoded',\n      },\n      body: \"targetblogid=\"+targetblogid+\"&method=getCollectionList&needViewCount=1&blogid=\"+targetblogid\n    }));\n     jsonData = JSON.parse(response)\n    }catch(e){\n          response = await fetch(postUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application\/x-www-form-urlencoded',\n      },\n      body: \"targetblogid=\"+targetblogid+\"&method=getCollectionList&needViewCount=1&blogid=\"+targetblogid\n    });\n       jsonData = await response.json();\n    }\n    showModal();\n    renderCollections(jsonData)\n}\n\n        function showApiPopup() {\n            document.getElementById('apiPopupOverlay').style.zIndex = \"9999\";\n            document.getElementById('modalOverlay').style.zIndex = \"1000\";\n            document.getElementById('apiPopupOverlay').style.display = 'flex';\n            document.getElementById('copySuccess').style.display = 'none';\n        }\n        \n        function closeApiPopup() {\n            document.getElementById('apiPopupOverlay').style.display = 'none';\n        }\n        \n        \/\/打开\n        function openUrl(t) {\n            try{\n                \n             if(t==2){\n               let url2 = \\`https:\/\/api.lofter.com\/oldapi\/post\/detail.api?product=lofter-android-8.3.20,{\"method\":\"POST\",\"body\":\"blogdomain=_blogid_${blogid}.lofter.com&postid=${postid}\"}\\`;\n               url2 = \\`legado:\/\/import\/addToBookshelf?src=$\\{encodeURIComponent(url2)},{\"origin\":\"📖Lofter\"}\\`;\n               window.open(url2)\n               return;\n            }\n                \n                \n            const textarea = document.getElementById('apiTextArea').value.split(\"::\");\n            let name = textarea[0].match(\/^..(.*)\/)[1];\n            let type = textarea[0].match(\/^(..)\/)[1];\n            \n            let num = null;\n            if(\/📖\/.test(type)){\n                num = \"(\"+document.querySelector('#apiPopup h3').textContent.match(\/(\\\\d+篇)\/)[1]+\")\";\n            }\n            \n            let url = textarea[1];\n            if(t==1){\n                toOpen(type,name,url,0,num)\n            }else if(t==0){\n                if(\/targetblogid=\/.test(url) && !url.includes(\"postCollection\")){\n                url = \\`http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=$\\{url.match(\/targetblogid=(\\\\d+)\/)[1]}&method=getBlogInfoDetail&returnData=1&limit=500&offset=0&checkpwd=1&needgetpoststat=1\"}\\`;\n                }\n                url = url.replace(\/{\\{.*?}}\/g,'0').replace(\/limit=\\\\d+\/g,'limit=500')\n                url = \\`legado:\/\/import\/addToBookshelf?src=$\\{encodeURIComponent(url)},{\"origin\":\"📖Lofter\"}\\`;\n                window.open(url)\n            }\n            \n            }catch(e){\n                java.log(e)\n            }\n        }\n        \n        \/\/ 复制文本\n        function selectAndCopy() {\n            const textarea = document.getElementById('apiTextArea');\n            textarea.select();\n            textarea.focus();\n            \n            try {\n                const successful = document.execCommand('copy');\n                if (successful) {\n                    showCopySuccess();\n                } else {\n                    fallbackCopy();\n                }\n            } catch (err) {\n                fallbackCopy();\n            }\n        }\n        \n        \/\/ 显示复制成功提示\n        function showCopySuccess() {\n            const successMsg = document.getElementById('copySuccess');\n            successMsg.style.display = 'block';\n            successMsg.textContent = '✅ 文本已复制到剪贴板';\n            \n            setTimeout(() => {\n                successMsg.style.display = 'none';\n            }, 3000);\n        }\n        \n        \/\/ 备用复制方法\n        function fallbackCopy() {\n            const textarea = document.getElementById('apiTextArea');\n            textarea.select();\n            textarea.focus();\n            \n            try {\n                navigator.clipboard.writeText(textarea.value)\n                    .then(() => {\n                        showCopySuccess();\n                    })\n                    .catch(() => {\n                        alert('复制失败,请手动复制文本');\n                    });\n            } catch (err) {\n                alert('请手动选择并复制文本');\n            }\n        }\n        \n        \/\/ 点击弹窗外关闭弹窗\n        document.getElementById('apiPopupOverlay').addEventListener('click', closeApiPopup);\n\n\nfunction toOpen(type,name,url,f,num){\n    let targetblogid = url.match(\/targetblogid=(\\\\d+)\/)?.[1];\n\tif(\/👤\/.test(type)){\n\t\t url = \\`http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\":\"POST\",\"body\":\"supportposttypes=1%2C2%2C3%2C4%2C5%2C6&targetblogid=$\\{targetblogid}&offset={\\{(page-1)*18}}&method=getPostLists&postdigestnew=1&returnData=1&limit=18&checkpwd=1&needgetpoststat=1\"}\\`;\n\t\t}\n        \n        url = String(url).replace(\/offset=\\\\d+\/g,'offset={\\{(page-1)*18}}').replace(\/limit=\\\\d+\/g,'limit=18');\n       document.querySelector(\"#apiPopup h3\").textContent= type+name+(\/📖\/.test(type)?(num??\"${postNum}\"):\"\");\n       \n                document.querySelector(\"textarea\").value=type+ name+\"::\"+url;\n                if(\/🏷\/.test(type)){\n                    document.querySelector(\"#postButton\").style.display = \"none\"\n                }else{\n                    document.querySelector(\"#postButton\").style.display = \"block\"\n                }\n                \n               showApiPopup();\n               \n        try{\n          if(f!==1){\n              if(\/📖\/.test(type)){\n                  run(\\`getCollectionSort(\"$\\{name}\",\"$\\{url.match(\/collectionid=(\\\\d+)\/)[1]}\",\"$\\{targetblogid}\")\\`).then(r=>java.open(\"sort\",r));\n              }else if(\/👤\/.test(type)){\n               run(\\`getUserSort(\"$\\{name}\",\"$\\{targetblogid}\")\\`).then(r=>java.open(\"sort\",r));\n            }else if(\/🏷\/.test(type)){\n                    run(\\`getTagSort(\"$\\{name}\")\\`).then(r=>java.open(\"sort\",r));\n              }\n          }\n        }catch(e){\n            \n        }\n\t} \n    \n function handleSubscribe(){\n      const textarea = document.getElementById('apiTextArea').value.split(\"::\");\n      let name = textarea[0].match(\/^..(.*)\/)[1];\n      let type = textarea[0].match(\/^(..)\/)[1];\n      let url = textarea[1];\n      url = url.replace(\/{\\{.*?}}\/,'0');\n      let id = url.match(\/collectionid=(\\\\d+)\/)?.[1]??url.match(\/blogid=(\\\\d+)\/)?.[1];\n       let s = String(source.getVariable());\n       s = \/{\/.test(s)?s:\"\";\n       let jsonData = JSON.parse(s || '{\"users\":[],\"collections\":[],\"grains\":[],\"tags\":[]}');\n\n      let existingUser;\n            try {\n                let u = {\n                    \"id\": id,\n                    \"name\":name,\n                    desc:\"\"                \n                   };\n                   \n                   if(type===\"📖\"){\n                       type = \"collections\";\n                       existingUser = jsonData[type].find(user => String(user.id) === id);\n                       if(existingUser){\n                           java.toast(\"订阅已存在\");\n                           return\n                       }\n                       let blogid = url.match(\/blogid=(\\\\d+)\/)?.[1];\n                       u.blogid = blogid;\n                       let postCollectionUrl = \"https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-8.3.20,\"+JSON.stringify({\"method\":\"POST\",\"body\":\"method=getCollectionDetail&offset=0&limit=15&targetblogid=\"+blogid+\"&collectionid=\"+id+\"&blogid=\"+blogid+\"&order=0\"});\n                       let data = java.ajax(postCollectionUrl);\n                       data = JSON.parse(data).response.collection;\n                       u.avatar = data.coverUrl;\n                       u.desc = data.postCount+\"篇 🏷\"+ data.tags.replace(\/,\/g,'🏷')+\" \"+data.description;\n                   }\n                   \n                 if(type === \"👤\"){\n                     type = \"users\";\n                     existingUser = jsonData[type].find(user => String(user.id) === id);\n                       if(existingUser){\n                           java.toast(\"订阅已存在\");\n                           return\n                       }\n                     let userUrl = \"https:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-8.3.20,\"+JSON.stringify({\"method\":\"POST\",\"body\":\"targetblogid=\"+id+\"&method=getBlogInfoDetail&returnData=1&checkpwd=1&needgetpoststat=1\"});\n                     let data = java.ajax(userUrl);\n                     data = JSON.parse(data).response.blogInfo;\n                     u.avatar = data.bigAvaImg;\n                     u.desc = ((data?.verifyBlog?.desc??\"\" )+\"<br>\"+ data.selfIntro).replace(\/^<br>\/,'')\n                 }\n                 \n                 \n                 if(type === \"users\" || type === \"collections\"){\n                    if (!existingUser) {\n                        jsonData[type].push(u);\n                        source.putVariable(JSON.stringify(jsonData));\n                        java.toast(\"订阅成功\");\n                       }\n                }else if(type === \"🏷\"){\n                    existingUser = jsonData[\"tags\"].find(user => String(user) === name);\n                    if(existingUser){\n                           java.toast(\"订阅已存在\");\n                           return\n                     }\n                    if (!existingUser) {\n                        jsonData[\"tags\"].push(name);\n                        source.putVariable(JSON.stringify(jsonData));\n                        java.toast(\"订阅成功\");\n                       }\n                }\n            } catch(err) {\n                console.log(err)\n                java.toast(\"订阅失败\");\n            }\n }\n<\/script>\n`;\n\nif(S(\"$..blogInfo.blogNickName\")==\"\"){\n\tresult = S(\"$..msg\")\n\t}\nresult = result.replace(\/(<p><br\\s*\\\/><\\\/p>){1,}\/g,'')\n}\n\n\nresult\n<\/js>\n##tbc\\.##<br>&lrm;<br>",
    "ruleDescription": "@js:\nif(\/newsearch\\\/blog.json\/.test(baseUrl) || String(java.get(\"prefix\"))==\"@\" || S(\"$.itemType\") ===\"38\" || baseUrl.includes(\"&t=2\")||baseUrl.includes(\"exploreblogs\")){\n    let url = `http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\":\"POST\",\"body\":\"supportposttypes=1%2C2%2C3%2C4%2C5%2C6&targetblogid=${S('$.blogId||$.blogInfo.blogId')}&offset={\\{(page-1)*18}}&method=getPostLists&postdigestnew=1&returnData=1&limit=18&checkpwd=1&needgetpoststat=1\"}`;\n    let info = `${S('$..authName')}<hr>${S('$..selfIntro')}`;\n    result = getHtmlto(S(\"$.blogNickName||$.blogInfo.blogNickName||$.title\"),info,S(\"$.bigAvaImg||$.blogInfo.bigAvaImg||$.img\"),\"👤\",url,S('$.blogId||$.blogInfo.blogId'));\n} else if(\/newsearch[^']+grain.json\/.test(baseUrl) || String(java.get(\"prefix\"))==\"%\"){\n    let grainurl = 'https:\/\/api.lofter.com\/api-grain\/grain\/getDetail.json?grainId='+S(\"$.id\")+'&offset=0';\n    let info = `${S('$.postCount')}篇🏷${S('$.tags')}\\n<hr>${S(\"$.description\")}`;\n    result = getHtmlto(S(\"$.name\"),info,S(\"$.coverUrl\"),\"📗\",grainurl);\n    \n}else if(\/newsearch[^']+collection.json|getCollectionList|postCollection\\\/tagPage\/.test(baseUrl) || String(java.get(\"prefix\"))==\"#\" ||String(java.get(\"prefix\")) == \"#\"){\n        blogid = '{{$.blogId}}';\n        id = '{{$.id}}';\n         let curl = 'https:\/\/api.lofter.com\/v1.1\/postCollection.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=' +blogid+'&method=getCollectionSimple&offset={\\{(page-1)*2000}}&limit=2000&blogid=' + blogid + '&collectionid=' + id + '&order=1\"}';\n         let info = `${S('$.postCount')}篇🏷${S('$.tags||$.tagList')}`\n         result = getHtmlto(S(\"$.name\"),info,S(\"$.coverUrl\"),\"📖\",curl)\n        curl = `legado:\/\/import\/addToBookshelf?src=${encodeURIComponent(curl)},{\"origin\":\"📖Lofter\"}`;\n}else {\n    result = \"\";\n}\nresult\n",
    "ruleImage": "{{$..firstImageUrl##.*?(https.*?)\"##$1###}}{{$..postView.firstImage.orign||$.postData.blogInfo.bigAvaImg||$..blogInfo.bigAvaImg||$..bigAvaImg||$..coverUrl||$.img}}##(http.*?)https?.*##$1\n<js>\nif(\/^http\/.test(result)){\nresult = result+\",\"+JSON.stringify({'headers':{'referer':\"http:\/\/www.lofter.com\",\"if-modified-since\":\"\"}});\n}\nresult\n<\/js>",
    "ruleLink": "@js:\ntry{\nif (String(java.get(\"prefix\")) == \"@\" ){\n        id = S('$.blogId');\n        result = 'http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\": \"POST\",\"body\":\"targetblogid=' + id + '&method=getBlogInfoDetail&returnData=1&checkpwd=1&needgetpoststat=1\"}'\n    } else if (String(java.get(\"prefix\")) == \"%\") {\n        result = `http:\/\/www.lofter.com@js:'data:grain;base64,${java.base64Encode(S(\"$.id\")+\"❌\"+S(\"$.userId\")+\"❌\"+S(\"$.name\"))},{\"type\":\"\"}'`;\n        result  = isL()?result:S(\"$.id\")+\"&\"+S(\"$.userId\");\n    } else if (String(java.get(\"prefix\")) == \"#\" || String(java.get(\"prefix\")) == \"#\") {\n        blogid = S('$.blogId');\n        id = S('$.id}}');\n        blogName = S('$.blogName}}');\n        result = `http:\/\/www.lofter.com@js:'data:collections;base64,${java.base64Encode(blogid+\"❌\"+id+\"❌\"+blogName+\"❌\"+S(\"$.name\"))},{\"type\":\"\"}'`;\n       result  = isL()?result:id+\"&\"+blogid;\n    }else if(baseUrl.includes(\"ranklist.json\")){\n        let title = String(S(\"$.title\")).replace(\/^#\\s*\/g,'');\n        let blogid = S(\"$.blogId\");\n        if(baseUrl.includes(\"t=0\")){\n            \/\/热搜词\n            result = `http:\/\/www.lofter.com@js:'data:hotsearch;base64,${java.base64Encode(title)},{\"type\":\"\"}'`;\n        }else if(baseUrl.includes(\"t=1\")){\n            \/\/LOFTER热文榜\n            result = \"https:\/\/api.lofter.com\/oldapi\/post\/detail.api?product=lofter-android-7.4.4\";\n            option = {\n                \"method\": \"POST\",\n                \"body\": \"targetblogid=\"+S(\"$.blogId\")+\"&postid=\" +  S(\"$.postId\")\n            }\n           result =  result + \",\" + JSON.stringify(option)\n           \n        }else if(baseUrl.includes(\"t=2\")){\n            \/\/神仙太太榜\n            result = `http:\/\/www.lofter.com@js:'data:hotuser;base64,${java.base64Encode(blogid)},{\"type\":\"\"}'`;\n        }else{\n            \/\/其他标签\n            result = `http:\/\/www.lofter.com@js:'data:hottag;base64,${java.base64Encode(title)},{\"type\":\"\"}'`;\n        }\n    }else{\n        url = S('$.post.blogId||$.blogId||$..postView.blogId');\n        id = S('$.post.id') || S('$.id') || S('$..postView.id');\n        \n        if (url.match(\/_blogid_\\d+\/)) {\n            main = url.match(\/_blogid_(\\d+)\/)[1];\n            body = \"targetblogid=\" + main + \"&postid=\" + id;\n            result = `https:\/\/api.lofter.com\/oldapi\/post\/detail.api?product=lofter-android-7.4.4,{\"method\":\"POST\",\"body\":\"' + String(body) + '\"}`;\n        } else {\n          \n            result = \"https:\/\/api.lofter.com\/oldapi\/post\/detail.api?product=lofter-android-7.4.4\";\n            option = {\n                \"method\": \"POST\",\n                \"body\": \"targetblogid=\"+url+\"&postid=\" + id\n            }\n           result =  result + \",\" + JSON.stringify(option)\n        }\n    };\nresult\n}catch(e){\n    java.log(e)\n}",
    "ruleNextPage": "<js>\nif(\/offset={\\{\\(page-1\\)\\s*\\*\\d+}\\}\/.test(baseUrl)){\n\tlet p = baseUrl.match(\/\\*(\\d+)\\}\/)[1];\n\tbaseUrl = baseUrl.replace(\/offset={\\{\\(page-1\\)\\s*\\*\\d+}\\}\/,'offset='+p);\n\t}else if(S(\"$.data.offset\")){\n\t\t  let offset = String(java.getString(\"$.data.offset\"));\n\t\t  if(offset!=-1){\n\t\t  \tbaseUrl = baseUrl.replace(\/offset=\\d+\/,'offset='+offset).replace(\/v2\\\/all\/,'all\/post');\n\t\t  \t}\n\t}else if(\/offset=\\d+\/.test(baseUrl)){\n\t\t offset =Number(baseUrl.match(\/offset=(\\d+)\/)[1]);\n    let limit = Number(baseUrl.match(\/limit=(\\d+)\/)[1]);\n    baseUrl = baseUrl.replace(\/offset=\\d+\/,'offset='+(offset+limit));\n\t\t}\n<\/js>",
    "rulePubDate": "$.post.publishTime||$.publishTime||$..postView.publishTime\n@js:\na=parseInt(result)>0?java.timeFormat(parseInt(result)):'';\nresult = S(\"$.score\")+(S(\"$.post.top\")===\"1\"?\"【🔝置顶】\":\"\")+ a+\" \"+ S(\"$.postCount\").replace(\/^[^\\d]+.*\/g,'')+\"篇•\"+S(\"$.post.tag||$.tagList||$..tags||$..tagList||$.commonUsedTags\").replace(\/\\n|\"*,\"*|\\[\"\/g,'🏷').replace(\/\"\\]|\\[\\]\/g,'')+\"📖\"+S(\"$.authName&&$.selfIntro&&$..$..postView.digest&&$.post.digest&&$.postDigest||$..selfIntro&&$..authName\");\nresult.replace(\/\\s+篇•|•$|<\\\/*[a-z]+.*?>|\\n|📖$\/g,' ')",
    "ruleTitle": "{{$..longInfo.title}}•{{$.post.title||$.post.noticeLinkTitle||$..postView.title||$..postView.digest||$.name||$.title||$.post.digest||$.blogNiceName||$.blogNickName||$.noticeLinkTitle||$.digest||$.blogInfo.blogNiceName||$.blogNickName||$.blogInfo.blogNickName||$.post.blogInfo.blogNickName||$.post.blogInfo.blogId||$.post.blogPageUrl}}{{S(\"$.icon\")?\"🔥\":\"\"}}\n<js>\nif(\/api-grain\/.test(baseUrl)&&!baseUrl.includes(\"list.json\")){\n\tresult = S(\"$..postView.title||$..postView.digest\");\n\tif(S(\"$..viewRankPublic\")==\"false\"){\n\t\tresult = result+\"【❌作品被删除】\"\n\t\t}\n}\na=result.replace(\/^(.{0,15})\/,'$1').replace(\/<.*?>\/g,'').replace(\/^•\/,'');\njava.put('text',a);\na<\/js>",
    "searchUrl": "@js:\nlet prefix = key.charAt(0);\njava.put(\"prefix\",prefix);\nlet offset = '{\\{(page-1) *' + (prefix === '%' ? '10}' : (prefix === '@' ? '10}' : '20}')) + '}';\nlet baseUrl = \"https:\/\/api.lofter.com\/newsearch\/\"\nswitch(prefix) {\n    case '@':\n        result = baseUrl+'blog.json?key=' + key.slice(1)+ '&limit=10&offset=' + offset;\n        break;\n    case '#':\n    case '#':\n        result = baseUrl+'collection.json?key=' + key.slice(1) + '&limit=20&offset=' + offset;\n        break;\n    case '%':\n        result = baseUrl+'grain.json?key='+key.slice(1)+'&limit=10&offset=' + offset;\n        break;\n    default:\n        let header = {\n            \"headers\": {\n                \"Content-Type\": \"application\/x-www-form-urlencoded;charset=utf-8\",\n                \"deviceid\": java.androidId(),\n                \"if-modified-since\": String(new Date()).replace(\/(.*?)\\s(.*?)\\s(.*?)\\s(.*?)GMT.*\/,'$1, $3 $2 $4 GMT')\n            }\n        };\n        result = baseUrl+'post.json?key=' + key + '&sortType=0&offset=' + offset + '&limit=20,' + JSON.stringify(header);\n}",
    "showWebLog": true,
    "singleUrl": false,
    "sortUrl": "🏷双女主::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *22}}&limit=22&firstpermalink=null&tag=双女主&type=new,{\"method\": \"POST\",\"body\":\"null\"}\n🏷橘气::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *18}}&limit=18&firstpermalink=null&tag=橘气&type=new,{\"method\": \"POST\",\"body\":\"null\"}\n🏷手机壁纸::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *22}}&limit=22&firstpermalink=null&tag=手机壁纸&type=new,{\"method\": \"POST\",\"body\":\"null\"}\n🏷百合文::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *18}}&limit=18&firstpermalink=null&tag=百合文&type=new,{\"method\": \"POST\",\"body\":\"null\"}\n🏷短视频::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *22}}&limit=22&firstpermalink=null&tag=短视频&type=new,{\"method\": \"POST\",\"body\":\"null\"}\n\n\n🔍搜索::{{let a=\"\";svg=String(java.base64Encode(`<svg width=\"1190\" height=\"300\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#ffffff\"\/><text x=\"220\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"50\" fill=\"#333\" font-weight=\"bold\">输入要搜索的内容,格式如下:<\/text><text x=\"150\" y=\"200\" font-family=\"Arial, sans-serif\" font-size=\"50\" fill=\"#333\" font-weight=\"bold\">文章名  @用户名  #合集名  %粮单名<\/text><text x=\"190\" y=\"290\" font-family=\"Arial, sans-serif\" font-size=\"30\" fill=\"#333\">下拉【🔍搜索】或刷新【🔍搜索】分类弹出输入框<\/text><\/svg>`));if(page==1){try{a=java.getVerificationCode('data:image\/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=source.getVariable()};source.setVariable(a);}else{a=source.getVariable()};key = String(a);let prefix = key.charAt(0);java.put(\"prefix\",prefix);let offset=0;let baseUrl = \"https:\/\/api.lofter.com\/newsearch\/\";switch(prefix) {case '@':result = baseUrl+'blog.json?key=' + key.slice(1)+ '&limit=10&offset=' + offset;break;case '#':case '#':result = baseUrl+'collection.json?key=' + key.slice(1) + '&limit=10&offset=' + offset;break;case '%':result = baseUrl+'grain.json?key='+key.slice(1)+'&limit=10&offset=' + offset;break;default:let header = {\"headers\": {\"Content-Type\": \"application\/x-www-form-urlencoded;charset=utf-8\",\"deviceid\": java.androidId(),\"if-modified-since\": String(new Date()).replace(\/(.*?)\\s(.*?)\\s(.*?)\\s(.*?)GMT.*\/,'$1, $3 $2 $4 GMT')} };result = baseUrl+'post.json?key=' + key + '&sortType=0&offset=' + offset + '&limit=10,' + JSON.stringify(header);};result}}\n\n👤砂上雪::http:\/\/api.lofter.com\/v2.0\/blogHomePage.api?product=lofter-android-7.4.4,{\"method\":\"POST\",\"body\":\"supportposttypes=1%2C2%2C3%2C4%2C5%2C6&blogdomain=taste-s.lofter.com&offset={{(page-1)*18}}&method=getPostLists&postdigestnew=1&returnData=1&limit=18&checkpwd=1&needgetpoststat=1\"}",
    "sourceComment": "配合使用改版阅读sigma效果更佳【先更新软件,再导入书源】\nhttps:\/\/loyc.xyz\/c\/legado.html\n\n下拉【🔍搜索】或刷新【🔍搜索】分类搜索\n\n🏷标签名::https:\/\/api.lofter.com\/oldapi\/tagPosts.api?product=lofter-android-7.4.4&method=newTagSearch&offset={{(page-1) *22}}&limit=22&firstpermalink=null&tag=标签名&type=new,{\"method\": \"POST\",\"body\":\"null\"}",
    "sourceGroup": "阅读",
    "sourceIcon": "https:\/\/is1-ssl.mzstatic.com\/image\/thumb\/Purple221\/v4\/af\/c2\/00\/afc200a4-978b-193a-a749-2151041ef09e\/AppIcon-1x_U007ephone-0-0-0-85-220-0.png\/492x0w.webp",
    "sourceName": "📖\nLofter",
    "sourceUrl": "Lofter",
    "startHtml": "<!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>LOFTER订阅<\/title>\n<\/head>\n<body>\n    <div class=\"container\">\n        <div class=\"sub-options\">\n            <div class=\"category-tabs\">\n                <button class=\"category-tab active\" data-category=\"user\">博主<\/button>\n                <button class=\"category-tab\" data-category=\"collection\">合集<\/button>\n                <button class=\"category-tab\" data-category=\"grain\">粮单<\/button>\n                <button class=\"category-tab\" data-category=\"tag\">标签<\/button>\n            <\/div>\n            <div class=\"search-box\">\n                <input type=\"text\" placeholder=\"搜索当前列表(搜索空内容显示全部)\">\n                <button class=\"search-btn\">搜索<\/button>\n            <\/div>\n        <\/div>\n\n        <div class=\"content-area\">\n            <div class=\"subscribe-list\" id=\"subscribe-list\">\n                <!-- 订阅列表-->\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <!-- 底部按钮区域 -->\n    <div class=\"bottom-buttons\">\n        <button class=\"bottom-button\" data-type=\"search\">\n            <span class=\"bottom-button-icon\">🔍<\/span>\n            <span class=\"bottom-button-text\">搜索<\/span>\n        <\/button>\n        <button class=\"bottom-button\" data-type=\"hot\">\n            <span class=\"bottom-button-icon\">🔥<\/span>\n            <span class=\"bottom-button-text\">榜单<\/span>\n        <\/button>\n        <button class=\"bottom-button\" data-type=\"hotlist\">\n            <span class=\"bottom-button-icon\">💡<\/span>\n            <span class=\"bottom-button-text\">发现<\/span>\n        <\/button>\n        <button class=\"bottom-button\" data-type=\"login\">\n            <span class=\"bottom-button-icon\">👤<\/span>\n            <span class=\"bottom-button-text\">支持<\/span>\n        <\/button>\n    <\/div>\n\n    <!-- 搜索弹窗 -->\n    <div class=\"search-modal\" id=\"search-modal\">\n        <div class=\"search-modal-content\">\n            <div class=\"search-modal-header\">\n                <h3 class=\"search-modal-title\">搜索<\/h3>\n                <button class=\"search-modal-close\" id=\"search-modal-close\">×<\/button>\n            <\/div>\n            <input type=\"text\" class=\"search-modal-input\" id=\"search-modal-input\" placeholder=\"输入搜索关键词\">\n            <div class=\"search-history\">\n                <div class=\"search-history-title\"><a>历史搜索<\/a> <span id=\"search-clear\" class=\"search-clear\">×清空历史<\/span><\/div>\n                \n                <div class=\"search-history-list\" id=\"search-history-list\">\n                    <!-- 历史搜索记录会通过JS动态生成 -->\n                <\/div>\n            <\/div>\n            <div class=\"search-modal-actions\">\n                <button class=\"search-modal-cancel\" id=\"search-modal-cancel\">取消<\/button>\n                <button class=\"search-modal-confirm\" id=\"search-modal-confirm\">确认<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <!-- 登录弹窗 -->\n    <div class=\"login-modal\" id=\"login-modal\">\n        <div class=\"login-modal-content\">\n            <div class=\"login-modal-header\">\n                <h3 class=\"login-modal-title\">登录<\/h3>\n                <button class=\"login-modal-close\" id=\"login-modal-close\">×<\/button>\n            <\/div>\n            \n            <div class=\"login-modal-actions\">\n                <button class=\"login-modal-my\" id=\"login-modal-my\">我的关注<\/button>\n                <button class=\"login-modal-cancel\" id=\"login-modal-cancel\">跳转登录<\/button>\n                <button class=\"login-modal-confirm\" id=\"login-modal-confirm\">退出登录<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <!-- 备注弹窗 -->\n    <div class=\"remark-modal\" id=\"remark-modal\">\n        <div class=\"remark-modal-content\">\n            <div class=\"remark-modal-header\">\n                <h3 class=\"remark-modal-title\">设置备注<\/h3>\n                <button class=\"remark-modal-close\" id=\"remark-modal-close\">×<\/button>\n            <\/div>\n            <input type=\"text\" class=\"remark-modal-input\" id=\"remark-modal-input\" placeholder=\"输入备注\">\n            <div class=\"remark-modal-actions\">\n                <button class=\"remark-modal-cancel\" id=\"remark-modal-cancel\">取消<\/button>\n                <button class=\"remark-modal-confirm\" id=\"remark-modal-confirm\">确认<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n<\/body>\n<\/html>",
    "startJs": "const baseApi = \"https:\/\/api.lofter.com\";\nconst ver = \"product=lofter-android-8.3.20\";\nlet s = source.getVariable();\ns = \/{\/.test(s)?s:\"\";\nconst mockData = JSON.parse(s || '{\"users\":[],\"collections\":[],\"grains\":[],\"tags\":[]}');\nlet startH = source.get(\"start\");\n\nlet findItems = findItem(mockData,startH);\nif(findItems.item){\n      handleItemClick(findItems.type,findItems.item);\t       \n     if(String(source.get(\"isStart\"))==\"1\"){\n\t        setTimeout(function() {\n            window.close()\n          },8) \n         }\n}\n\n\/\/ 当前数据状态\nlet currentData = [...mockData.users];\nlet currentCategory = 'user';\nlet remarkItemId = null;\nlet searchHistory = JSON.parse(source.get('lofterSearchHistory') || '[]');\nlet selectedItemId = null;\nlet isSortMode = false;\n\n\nfunction findItem(data, startH) {\n  \/\/ 检查是否是 users 中的 id\n  const foundUser = data.users.find(user => user.id === startH);\n  if (foundUser) {\n    return { item: foundUser, type: 'user' };\n  }\n  \n  \/\/ 检查是否是 collections 中的 id\n  const foundCollection = data.collections.find(collection => collection.id === startH);\n  if (foundCollection) {\n    return { item: foundCollection, type: 'collection' };\n  }\n  \n  \/\/ 检查是否是 grains 中的 id\n  const foundGrain = data.grains.find(grain => grain.id === startH);\n  if (foundGrain) {\n    return { item: foundGrain, type: 'grain' };\n  }\n  \n  \/\/ 检查是否是 tags 中的文字\n  if (Array.isArray(data.tags)) {\n    const foundTag = data.tags.find(tag => tag === startH);\n    if (foundTag) {\n      return { item: foundTag, type: 'tag' };\n    }\n  }\n  \n  \/\/ 如果没有找到\n  return { item: null, type: null };\n}\n\nfunction saveDataToJson() {\n    switch(currentCategory) {\n        case 'user':\n            mockData.users = [...currentData];\n            break;\n        case 'collection':\n            mockData.collections = [...currentData];\n            break;\n        case 'grain':\n            mockData.grains = [...currentData];\n            break;\n        case 'tag':\n            mockData.tags = [...currentData];\n            break;\n    }\n    source.putVariable(JSON.stringify(mockData));\n}\n\n\/\/点击列表跳转对应\nfunction handleItemClick(category, item) {\n    let url,name;\n    switch(category) {\n        case 'user':\n            run(`getUserSort(\"${item.name}\",\"${item.id}\");`).then(r=>java.open(\"sort\",r));\n            return;\n        case 'collection':\n            run(`getCollectionSort(\"${item.name}\",\"${item.id}\",\"${item.blogid}\");`).then(r=>java.open(\"sort\",r));\n            return;\n        case 'tag':\n            run(`getTagSort(\"${item}\");`).then(r=>java.open(\"sort\",r));\n            return;\n        case 'grain':\n           url = JSON.stringify({\n                [\"📗《\"+item.name+\"》\"]:\"https:\/\/api.lofter.com\/api-grain\/grain\/getDetail.json?grainId=\"+item.id+\"&offset=0\"\n            })\n            java.open(\"sort\", url,item.name);\n            break;\n    }\n}\n\ndocument.addEventListener('DOMContentLoaded', function() {\n    renderSubscribeContent(currentCategory);\n    const categoryTabs = document.querySelectorAll('.category-tab');\n    categoryTabs.forEach(tab => {\n        tab.addEventListener('click', function() {\n            categoryTabs.forEach(t => t.classList.remove('active'));\n            this.classList.add('active');\n            const category = this.getAttribute('data-category');\n            currentCategory = category;\n            switch(category) {\n                case 'user':\n                    currentData = [...mockData.users];\n                    break;\n                case 'tag':\n                    currentData = [...mockData.tags];\n                    break;\n                case 'grain':\n                    currentData = [...mockData.grains];\n                    break;\n                case 'collection':\n                    currentData = [...mockData.collections];\n                    break;\n            }\n            renderSubscribeContent(category);\n        });\n    });\n    \n    const searchBtn = document.querySelector('.search-btn');\n    searchBtn.addEventListener('click', function() {\n        const searchInput = document.querySelector('.search-box input');\n        const searchText = searchInput.value.toLowerCase();\n        const filteredData = currentData.filter(item => \n            item.name.toLowerCase().includes(searchText) || \n            item.desc.toLowerCase().includes(searchText)\n        );\n        \n        renderSubscribeList(filteredData);\n    });\n    \n    const bottomButtons = document.querySelectorAll('.bottom-button');\n    bottomButtons.forEach(button => {\n        button.addEventListener('click', function() {\n            const type = this.getAttribute('data-type');\n            handleBottomButtonClick(type);\n        });\n    });\n    \n    const searchModal = document.getElementById('search-modal');\n    const searchModalClose = document.getElementById('search-modal-close');\n    const searchModalCancel = document.getElementById('search-modal-cancel');\n    const searchModalConfirm = document.getElementById('search-modal-confirm');\n    const searchModalInput = document.getElementById('search-modal-input');\n    const searchclear = document.getElementById(\"search-clear\")\n    \n    searchModalClose.addEventListener('click', closeModal);\n    searchModalCancel.addEventListener('click', closeModal);\n    \n    searchModalConfirm.addEventListener('click', function() {\n        const searchText = searchModalInput.value.trim();\n        if (searchText) {\n            addToSearchHistory(searchText);\n            run(`getSearchSort(\"${searchText}\")`).then(r=>java.open(\"sort\",r))\n            closeModal();\n        }\n    });\n    \n    \n    const remarkModal = document.getElementById('remark-modal');\n    const remarkModalClose = document.getElementById('remark-modal-close');\n    const remarkModalCancel = document.getElementById('remark-modal-cancel');\n    const remarkModalConfirm = document.getElementById('remark-modal-confirm');\n    const remarkModalInput = document.getElementById('remark-modal-input');\n    \n    remarkModalClose.addEventListener('click', closeRemarkModal);\n    remarkModalCancel.addEventListener('click', closeRemarkModal);\n    remarkModalConfirm.addEventListener('click', function() {\n        const remarkText = remarkModalInput.value.trim();\n        if (remarkItemId) {\n            updateRemarkName(remarkItemId, remarkText);\n            closeRemarkModal();\n        }\n    });\n    \n    const contentArea = document.querySelector('.content-area');\n    let startX = 0;\n    let endX = 0;\n    \n    contentArea.addEventListener('touchstart', function(e) {\n        startX = e.touches[0].clientX;\n    }, { passive: true });\n    \n    contentArea.addEventListener('touchmove', function(e) {\n        const currentX = e.touches[0].clientX;\n        const diffX = currentX - startX;\n    }, { passive: false });\n    \n    contentArea.addEventListener('touchend', function(e) {\n        const endX = e.changedTouches[0].clientX;\n        const diffX = endX - startX;\n        const threshold = 50; \n        \n        if (Math.abs(diffX) > threshold) {\n            const currentTab = document.querySelector('.category-tab.active');\n            const tabs = Array.from(document.querySelectorAll('.category-tab'));\n            const currentIndex = tabs.indexOf(currentTab);\n            \n            if (diffX > 0 && currentIndex > 0) {\n                tabs[currentIndex - 1].click();\n            } else if (diffX < 0 && currentIndex < tabs.length - 1) {\n                tabs[currentIndex + 1].click();\n            }\n        }\n    }, { passive: true });\n});\n\nfunction getHotUrl(type){\n    return `${m}\/api\/container\/getIndex?containerid=${encodeURIComponent(\"106003type=25&t=3&disable_hot=1&filter_type=\"+type)}&title=微博热搜&show_cache_when_error=1&extparam=${encodeURIComponent(\"seat=1&lcate=1001&mi_cid=100103&filter_type=realtimehot&pos=0_0&c_type=30&region_relas_conf=0&dgr=0&cate=10103&display_time=\"+parseInt(Date.now()\/1000)+\"&pre_seqid=\"+Date.now()+\"020423224\")}`;\n}\n\n\n\/\/ 渲染订阅内容\nfunction renderSubscribeContent(category) {\n    let data = [];\n    \n    if (category === 'user') {\n        data = [...mockData.users];\n    } else if (category === 'tag') {\n        data = [...mockData.tags];\n        renderSubscribeTagList(data);\n        return;\n    } else if (category === 'collection') {\n        data = [...mockData.collections];\n    } else if (category === 'grain') {\n        data = [...mockData.grains];\n    }\n    renderSubscribeList(data);\n}\n\n\n\/\/ 渲染标签列表\nfunction renderSubscribeTagList(data){\n     currentCategory = \"tag\";\n     const subscribeList = document.getElementById('subscribe-list');\n     subscribeList.innerHTML = '';\n     \n     data.forEach(x=>{\n         const subscribeItem = document.createElement('div');\n         subscribeItem.className = 'subscribe-tag';\n         subscribeItem.innerHTML = `<span class=\"subscribe-tagname\">${x}<\/span>`;\n         const subscribeIdel = document.createElement('span');\n         subscribeIdel.className = 'subscribe-del';\n         subscribeIdel.textContent = \"×\";\n         subscribeItem.appendChild(subscribeIdel);\n         subscribeList.appendChild(subscribeItem);\n     });\n     const subscribeAddTag = document.createElement('div');\n     subscribeAddTag.className = 'subscribe-tag';\n     subscribeAddTag.innerHTML = '<span class=\"addtagname\" contenteditable=\"true\">输入标签<\/span><span class=\"addtag\">+<\/span>';\n     subscribeList.appendChild(subscribeAddTag);\n     \nsubscribeAddTag.querySelector(\".addtagname\").addEventListener('blur', function() {\n  const text = this.textContent.trim();\n  if (!text) this.textContent = '输入标签';\n});\n\nsubscribeList.querySelectorAll(\".subscribe-tag\").forEach(tag=>{\n          tag.addEventListener('click', function(e) {\n              if(!e.target.classList.contains(\"addtag\") && !e.target.closest('.addtagname')){\n                  let tagname = this.closest(\".subscribe-tag\").textContent.replace(\/×$\/g,'');\n                  handleItemClick(currentCategory, tagname);\n              }\n      })\n});\n        \n        subscribeList.querySelectorAll(\".subscribe-del\").forEach(x=>{\n            x.addEventListener('click', function(e) {\n                e.stopPropagation();\n                let tagname = this.closest(\".subscribe-tag\").textContent.replace(\/×$\/g,'');\n                if(confirm(\"确定要删除【\"+tagname+\"】这个标签吗?\")){\n                    const index = data.findIndex(item =>item === tagname);\n                    if (index !== -1) {\n                        data.splice(index, 1);\n                        currentData = data; \n                        renderSubscribeTagList(currentData);\n                        saveDataToJson();\n                        java.toast(`已删除标签: ${tagname}`);\n                       } else {\n                           java.toast(`未找到标签: ${tagname}`);\n                       }\n                    }\n                 })\n        })\n        \n        \n        subscribeList.querySelector(\".addtag\").addEventListener('click', function(e) {\n            e.stopPropagation();\n            let name = document.querySelector(\".addtagname\").textContent;\n            if(name.trim()){\n                if(data.indexOf(name) === -1) {\n                    data.push(name);\n                    currentData = data; \n                    renderSubscribeTagList(currentData);\n                    saveDataToJson();\n                    java.toast(\"添加成功\");\n                 } else {\n                     java.toast(\"已存在相同标签\");\n                   }\n                 }\n              });\n}\n\n\/\/ 渲染订阅列表\nfunction renderSubscribeList(data) {\n    const subscribeList = document.getElementById('subscribe-list');\n    subscribeList.innerHTML = '';\n    \n    data.forEach((item, index) => {\n        const subscribeItem = document.createElement('div');\n        subscribeItem.className = 'subscribe-item';\n        subscribeItem.setAttribute('data-id', item.id);\n        subscribeItem.setAttribute('data-index', index);\n        const avatarContent = item.avatar ? \n            `<img src=\"${item.avatar}\" alt=\"${item.name}\">` : \n            item.name.charAt(0);\n        \n        const displayName = item.remarkName ?(item.name + \" (\"+item.remarkName+\")\"):item.name;\n        \n        subscribeItem.innerHTML = `\n            <div class=\"subscribe-avatar\">${avatarContent}<\/div>\n            <div class=\"subscribe-details\">\n                <div class=\"subscribe-title\">${displayName}<\/div>\n                <div class=\"subscribe-desc\">${item.desc}<\/div>\n            <\/div>\n            <div class=\"subscribe-actions\">\n                <button class=\"subscribe-action delete\" data-action=\"delete\" title=\"删除\">❎<\/button>\n                <button class=\"subscribe-action remark\" data-action=\"remark\" title=\"设置备注\">🆔<\/button>\n                <button class=\"subscribe-action sort\" data-action=\"sort\" title=\"排序\">↕️<\/button>\n            <\/div>\n        `;\n        \n        if (isSortMode) {\n            const swapButton = document.createElement('button');\n            swapButton.className = 'subscribe-action swap';\n            swapButton.setAttribute('data-action', 'swap');\n            swapButton.setAttribute('title', '交换位置');\n            swapButton.textContent = '⇄';\n            subscribeItem.querySelector('.subscribe-actions').appendChild(swapButton);\n            \n            if (item.id === selectedItemId) {\n                subscribeItem.classList.add('selected');\n            }\n        }\n        \n        subscribeList.appendChild(subscribeItem);\n    });\n    \n    bindSubscribeActions();\n    if (!isSortMode) {\n        bindItemClickEvents();\n    }\n}\n\nfunction bindItemClickEvents() {\n    const subscribeItems = document.querySelectorAll('.subscribe-item');\n    \n    subscribeItems.forEach(item => {\n        item.addEventListener('click', function(e) {\n            if (e.target.classList.contains('subscribe-action')) {\n                return;\n            }\n            \n            const itemId = this.getAttribute('data-id');\n            const currentItem = currentData.find(item => item.id === itemId);\n            \n            if (currentItem) {\n                handleItemClick(currentCategory, currentItem);\n            }\n        });\n    });\n}\n\nfunction bindSubscribeActions() {\n    const deleteButtons = document.querySelectorAll('.subscribe-action.delete');\n    const remarkButtons = document.querySelectorAll('.subscribe-action.remark');\n    const sortButtons = document.querySelectorAll('.subscribe-action.sort');\n    const swapButtons = document.querySelectorAll('.subscribe-action.swap');\n    const subscribeItems = document.querySelectorAll('.subscribe-item');\n    deleteButtons.forEach(button => {\n        button.addEventListener('click', function(e) {\n            e.stopPropagation();\n            const itemElement = this.closest('.subscribe-item');\n            const itemId = itemElement.getAttribute('data-id')\n            if (confirm('确定要删除这个订阅吗?')) {\n                deleteSubscribeItem(itemId);\n            }\n        });\n    });\n    \n    remarkButtons.forEach(button => {\n        button.addEventListener('click', function(e) {\n            e.stopPropagation();\n            const itemElement = this.closest('.subscribe-item');\n            const itemId = itemElement.getAttribute('data-id');\n            const currentName = itemElement.querySelector('.subscribe-title').textContent\n            \n            openRemarkModal(itemId, currentName);\n        });\n    });\n    \n    sortButtons.forEach(button => {\n        button.addEventListener('click', function(e) {\n            e.stopPropagation();\n            toggleSortMode();\n        });\n    });\n    \n    swapButtons.forEach(button => {\n        button.addEventListener('click', function(e) {\n            e.stopPropagation();\n            const itemElement = this.closest('.subscribe-item');\n            const itemId = itemElement.getAttribute('data-id');\n            \n            handleSwapItem(itemId);\n        });\n    });\n    \n    if (isSortMode) {\n        subscribeItems.forEach(item => {\n            item.addEventListener('click', function(e) {\n                if (e.target.classList.contains('subscribe-action')) return;\n                \n                const itemId = this.getAttribute('data-id');\n                handleSelectItem(itemId);\n            });\n        });\n    }\n}\n\nfunction toggleSortMode() {\n    isSortMode = !isSortMode;\n    selectedItemId = null;\n    \n    if (isSortMode) {\n        alert('已进入排序模式,请先点击要移动的项目,再点击目标项目的交换按钮');\n    } else {\n        alert('已退出排序模式');\n    }\n    \n    renderSubscribeList(currentData);\n}\n\nfunction handleSelectItem(itemId) {\n    if (!isSortMode) return;\n    \n    selectedItemId = itemId;\n    \n    renderSubscribeList(currentData);\n}\n\nfunction handleSwapItem(targetItemId) {\n    if (!isSortMode || !selectedItemId) {\n        alert('请先选择要移动的项目');\n        return;\n    }\n    \n    if (selectedItemId === targetItemId) {\n        alert('不能与自己交换位置');\n        return;\n    }\n    \n    const selectedIndex = currentData.findIndex(item => item.id === selectedItemId);\n    const targetIndex = currentData.findIndex(item => item.id === targetItemId);\n    \n    if (selectedIndex === -1 || targetIndex === -1) return;\n    \n    [currentData[selectedIndex], currentData[targetIndex]] = \n        [currentData[targetIndex], currentData[selectedIndex]];\n    \n    selectedItemId = null;\n    renderSubscribeList(currentData);\n    saveDataToJson();\n}\n\n\nfunction deleteSubscribeItem(itemId) {\n    currentData = currentData.filter(item => item.id !== itemId);\n    renderSubscribeList(currentData);\n    saveDataToJson();\n}\n\nfunction openRemarkModal(itemId, currentName) {\n    remarkItemId = itemId;\n    const remarkModal = document.getElementById('remark-modal');\n    const remarkModalInput = document.getElementById('remark-modal-input');\n    \n    remarkModalInput.value = currentName;\n    remarkModal.classList.add('active');\n    remarkModalInput.focus();\n}\n\nfunction closeRemarkModal() {\n    const remarkModal = document.getElementById('remark-modal');\n    const remarkModalInput = document.getElementById('remark-modal-input');\n    \n    remarkModal.classList.remove('active');\n    remarkModalInput.value = '';\n    remarkItemId = null;\n}\n\nfunction updateRemarkName(itemId, remarkName) {\n    const itemIndex = currentData.findIndex(item => item.id === itemId);\n    if (itemIndex !== -1) {\n        currentData[itemIndex].remarkName = remarkName;\n    }\n    \n    renderSubscribeList(currentData);\n    saveDataToJson();\n}\n\nfunction handleBottomButtonClick(type) {\n    switch (type) {\n        case 'search':\n            const searchModal = document.getElementById('search-modal');\n            searchModal.classList.add('active');\n            document.getElementById('search-modal-input').focus();\n            renderSearchHistory();\n            break;\n        case 'hot':\n            url = JSON.stringify({\n                \"热词榜\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=0\",\n                \"LOFTER热文榜\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=1\",\n                \"神仙太太榜\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=2\",\n                \"游戏创作榜\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=3\",\n                \"热门影视榜\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=4\",\n                \"二次元创作榜单\":\"https:\/\/api.lofter.com\/newapi\/hotsearch\/ranklist.json?\"+ver+\"&t=5\"\n            });\n            java.open(\"sort\", url)\n            break;\n        case 'hotlist':\n            url = JSON.stringify({\n                \"推荐\":`${baseApi}\/recommend\/exploreRecom.json?product=${ver},{\"method\":\"POST\",\"body\":\"offset=0&feedTime=0&count=0\"}`,\n                \"文学\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=1538118079721&offset=0&feedTime=0&count=0\"}`,\n                \"绘画\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=1370406202794&offset=0&feedTime=0&count=0\"}`,\n                \"影视\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=1442207751226&offset=0&feedTime=0&count=0\"}`,\n                \"二次元\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=1370406175120&offset=0&feedTime=0&count=0\"}`,\n                \"乙游\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=18244400&offset=0&feedTime=0&count=0\"}`,\n                \"娱乐\":`${baseApi}\/recommend\/domainPosts.json?${ver},{\"method\":\"POST\",\"body\":\"domainId=1430907486999&offset=0&feedTime=0&count=0\"}`,\n                \"视频\":`${baseApi}\/recommend\/videoFlow.json?offset=0&limit=10`,\n            })\n            java.open(\"sort\", url);\n            break;\n        case 'login':\n            java.showPhoto(\"https:\/\/gitee.com\/guaner001125\/booksource\/raw\/master\/%E5%9B%BE%E7%89%87\/guaner.webp\")\n            break;\n    }\n}\n\nfunction renderSearchHistory() {\n    const searchHistoryList = document.getElementById('search-history-list');\n    searchHistoryList.innerHTML = '';\n    \n    if (searchHistory.length === 0) {\n        searchHistoryList.innerHTML = '<div style=\"color: #999; font-size: 14px;\">暂无搜索历史<\/div>';\n        return;\n    }\n    \n    const recentHistory = searchHistory.slice(-10).reverse();\n    \n    recentHistory.forEach(item => {\n        const historyItem = document.createElement('div');\n        historyItem.className = 'search-history-item';\n        historyItem.textContent = item;\n        \n        historyItem.addEventListener('click', function() {\n            document.getElementById('search-modal-input').value = item;\n        });\n        \n        searchHistoryList.appendChild(historyItem);\n    });\n}\n\ndocument.addEventListener('DOMContentLoaded', function() {\n            const clearButton = document.querySelector('.search-clear');\n            if (clearButton) {\n                clearButton.addEventListener('click', function() {\n                    source.put('lofterSearchHistory', '');\n                    searchHistory = [];\n                    renderSearchHistory()\n                });\n            }\n        });\n\nfunction addToSearchHistory(searchText) {\n    \n    searchHistory = searchHistory.filter(item => item !== searchText);\n    searchHistory.push(searchText);\n    if (searchHistory.length > 50) {\n        searchHistory = searchHistory.slice(-50);\n    }\n    source.put('lofterSearchHistory', JSON.stringify(searchHistory));\n}\n\nfunction closeModal() {\n    document.getElementById('search-modal').classList.remove('active');\n    document.getElementById('search-modal-input').value = '';\n    document.getElementById('login-modal').classList.remove('active');\n}\n",
    "startStyle": ":root{\n\t --btn-active-color:#019D94;\n     --btn-text-color:#fff;\n     --btn-hover-color:#16C4BC\n}\n.subscribe-tag {\n    padding: 5px 15px;\n    margin: 4px;\n    background-color: #f9f9f9;\n    display: inline-block; \n    white-space: nowrap;\n     border-radius: 20px;\n     border:1px solid #ddd;\n     color:#000\n}\n.addtag{\n   \tpadding: 5px 10px;\n    margin-left: 8px;\n\t}\n\n.addtagname{\n  display: inline-block;\n  min-width: 20px; \n  outline: none;\n}\n\t\n.subscribe-tag:hover{\n\tbackground:var(--btn-active-color);\n\tcolor:var(--btn-text-color);\n\tborder:1px solid var(--btn-active-color);\n\t}\n\n\n.subscribe-del{\n\tpadding:3px;\n\tmargin-left:10px\n\t}\n\n* {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n            font-family: \"PingFang SC\", \"Microsoft YaHei\", sans-serif;\n        }\n\n        body {\n            background-color: #f5f5f5;\n            color: #333;\n            line-height: 1.5;\n            padding-bottom: 60px;\n        }\n\n        .container {\n            max-width: 480px;\n            margin: 0 auto;\n            background-color: #fff;\n            min-height: 100vh;\n            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n            display: flex;\n            flex-direction: column;\n        }\n\n        \/* 子选项区域 - 固定在顶部 *\/\n        .sub-options {\n            background-color: #f9f9f9;\n            padding: 10px 15px;\n            border-bottom: 1px solid #e6e6e6;\n            position: sticky;\n            top: 0;\n            z-index: 10;\n            box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n        }\n\n        .category-tabs {\n            display: flex;\n            justify-content: center;\n            margin-bottom: 10px;\n            gap: 10px;\n        }\n\n        .category-tab {\n            padding: 8px 15px;\n            font-size: 12px;\n            color: #666;\n            cursor: pointer;\n            border-radius: 15px;\n            background-color: #fff;\n            border: 1px solid #ddd;\n            transition: all 0.3s ease;\n        }\n\n        .category-tab.active {\n            background-color: var(--btn-active-color);\n            color: var(--btn-text-color);\n        }\n\n        .category-tab:hover {\n            transform: translateY(-1px);\n            box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n        }\n\n        .search-box {\n            display: flex;\n            max-width: 400px;\n            margin: 0 auto;\n        }\n\n        .search-box input {\n            flex: 1;\n            padding: 8px 10px;\n            border: 1px solid #ddd;\n            border-radius: 3px 0 0 3px;\n            font-size: 12px;\n            transition: border-color 0.3s;\n        }\n\n        .search-box input:focus {\n            outline: none;\n            border-color: var(--btn-active-color);\n        }\n\n        .search-btn {\n            background-color: var(--btn-active-color);\n            color: var(--btn-text-color);\n            border: none;\n            padding: 0 15px;\n            border-radius: 0 3px 3px 0;\n            cursor: pointer;\n            transition: background-color 0.3s;\n        }\n\n        .search-btn:hover {\n            background-color: var(--btn-hover-color);\n        }\n\n        \/* 内容区域 *\/\n        .content-area {\n            padding: 15px;\n            flex: 1;\n            overflow-y: auto;\n        }\n        \n        \/* 底部按钮区域 *\/\n        .bottom-buttons {\n            position: fixed;\n            bottom: 0;\n            left: 0;\n            right: 0;\n            display: flex;\n            background-color: #fff;\n            border-top: 1px solid #e6e6e6;\n            z-index: 100;\n            box-shadow: 0 -2px 10px rgba(0,0,0,0.05);\n        }\n        \n        .bottom-button {\n            flex: 1;\n            padding: 12px 5px;\n            border: none;\n            background: none;\n            font-size: 12px;\n            cursor: pointer;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            transition: all 0.3s;\n        }\n        \n        .bottom-button:hover {\n            background-color: #f5f5f5;\n        }\n        \n        .bottom-button-icon {\n            font-size: 14px;\n            margin-bottom: 4px;\n        }\n        \n        .bottom-button-text {\n            font-size: 12px;\n        }\n\n        \/* 订阅列表 *\/\n        .subscribe-list {\n            margin-top: 15px;\n        }\n\n        .subscribe-item {\n            display: flex;\n            align-items: center;\n            padding: 12px;\n            background-color: #f9f9f9;\n            border-radius: 8px;\n            margin-bottom: 10px;\n            transition: all 0.3s;\n            box-shadow: 0 2px 3px rgba(0,0,0,0.1);\n        }\n\n        .subscribe-item:hover {\n            border-left: 4px solid var(--btn-active-color);  \n            margin-left: -4px; \n            padding-left: 4px; \n            box-shadow: 0 2px 10px rgba(0,0,0,0.15);\n        }\n\n        .subscribe-item.sort-mode {\n            background-color: #f0f0f0;\n        }\n\n        .subscribe-item.selected {\n            background-color: #ffe0b2;\n            border: 2px solid #ff8200;\n        }\n\n        .subscribe-avatar {\n            \n            box-shadow: 0 2px 5px rgba(0,0,0,0.15);\n            width: 40px;\n            height: 40px;\n            border-radius: 5px;\n            background-color: #e6e6e6;\n            margin-right: 12px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            font-size: 14px;\n            color: #999;\n            overflow: hidden;\n            flex-shrink: 0;\n        }\n\n        .subscribe-avatar img {\n            width: 100%;\n            height: 100%;\n            object-fit: cover;\n        }\n\n        .subscribe-details {\n            flex: 1;\n            min-width: 0;\n        }\n\n        .subscribe-title {\n            font-size: 12px;\n            font-weight: 500;\n            margin-bottom: 5px;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            white-space: nowrap;\n        }\n\n.subscribe-desc {\n    font-size: 10px;\n    color: #999;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    display: -webkit-box;\n    -webkit-line-clamp: 3; \n    -webkit-box-orient: vertical;\n    line-height: 1.2; \n}\n\n\n        \/* 更新:功能按钮垂直排列 *\/\n        .subscribe-actions {\n            display: flex;\n            flex-direction: column;\n            gap: 5px;\n            flex-shrink: 0;\n            margin-left: 10px;\n        }\n\n        .subscribe-action {\n            background:none;\n            border:none;\n            padding: 4px;\n            font-size: 10px;\n            cursor: pointer;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            width: 12px;\n            height: 12px;\n            transition: all 0.3s;\n        }\n\n        .subscribe-action:hover {\n            transform: scale(1.1);\n        }\n\n        .subscribe-action.delete {\n            color: #ff3b30;\n            \n        }\n\n        .subscribe-action.remark {\n            color: #007aff;\n            \n        }\n\n        .subscribe-action.sort {\n            color: #34c759;\n          \n        }\n\n        .subscribe-action.swap {\n            color: #ff8200;\n           \n        }\n\n        \/* 搜索弹窗 *\/\n        .search-modal,.login-modal {\n            display: none;\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background-color: rgba(0, 0, 0, 0.5);\n            z-index: 1000;\n            align-items: center;\n            justify-content: center;\n        }\n\n        .search-modal.active,.login-modal.active{\n            display: flex;\n        }\n\n        .search-modal-content,.login-modal-content {\n            background-color: #fff;\n            width: 90%;\n            max-width: 400px;\n            border-radius: 12px;\n            padding: 20px;\n            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n            animation: modalSlideIn 0.3s ease;\n        }\n\n        @keyframes modalSlideIn {\n            from { transform: translateY(-20px); opacity: 0; }\n            to { transform: translateY(0); opacity: 1; }\n        }\n\n        .search-modal-header,.login-modal-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 15px;\n            padding-bottom: 10px;\n            border-bottom: 1px solid #e6e6e6;\n        }\n\n        .search-modal-title,.login-modal-title {\n            font-size: 14px;\n            font-weight: 600;\n        }\n\n        .search-modal-close,.login-modal-close {\n            background: none;\n            border: none;\n            font-size: 16px;\n            cursor: pointer;\n            color: #999;\n            transition: color 0.3s;\n        }\n\n        .search-modal-close:hover {\n            color: #333;\n        }\n\n        .search-modal-input {\n            width: 100%;\n            padding: 12px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            font-size: 12px;\n            margin-bottom: 15px;\n            transition: border-color 0.3s;\n        }\n\n        .search-modal-input:focus {\n            outline: none;\n            border-color: var(--btn-active-color);\n        }\n\n        .search-history {\n            margin-bottom: 20px;\n        }\n\/*\n        .search-history-title {\n            font-size: 14px;\n            color: #666;\n            margin-bottom: 10px;\n        }\n  *\/      \n        .search-history-title {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 20px;\n            padding-bottom: 15px;\n            border-bottom: 1px solid #f0f0f0;\n        }\n        .search-clear {\n            background-color: #f0f0f0;\n            color: #666;\n            padding: 8px 15px;\n            border-radius: 20px;\n            cursor: pointer;\n            font-size: 12px;\n            transition: all 0.3s ease;\n            display: flex;\n            align-items: center;\n            gap: 5px;\n        }\n        .search-clear:hover {\n            background-color: #e0e0e0;\n            transform: translateY(-2px);\n            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n        }\n        .search-history-list {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 8px;\n        }\n\n        .search-history-item {\n            background-color: #f5f5f5;\n            padding: 6px 12px;\n            border-radius: 15px;\n            font-size: 12px;\n            cursor: pointer;\n            transition: all 0.3s;\n        }\n\n        .search-history-item:hover {\n            background-color: #e6e6e6;\n        }\n\n        .search-modal-actions {\n            display: flex;\n            justify-content: flex-end;\n            gap: 10px;\n        }\n        \n        .login-modal-actions{\n            justify-content: center;\n            display: flex;\n            gap: 10px;\n        }\n        \n        .search-modal-cancel,.login-modal-cancel {\n            background: none;\n            border: 1px solid #ddd;\n            padding: 10px 20px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 12px;\n            transition: all 0.3s;\n        }\n        \n        .login-modal-cancel{\n            background-color: var(--btn-active-color);\n            color: var(--btn-text-color);\n            border: none;\n        }\n        \n        .search-modal-cancel:hover {\n            background-color: #f5f5f5;\n        }\n\n        .search-modal-confirm,.login-modal-confirm,.login-modal-my{\n            background-color: var(--btn-active-color);\n            color: var(--btn-text-color);\n            border: none;\n            padding: 10px 20px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 12px;\n            transition: background-color 0.3s;\n        }\n        \n        .login-modal-confirm,.login-modal-my{\n            background: none;\n            border: 1px solid #ddd;\n            color:#000\n        }\n        \n        .search-modal-confirm:hover {\n            background-color: var(--btn-hover-color);\n        }\n\n        \/* 备注弹窗 *\/\n        .remark-modal {\n            display: none;\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background-color: rgba(0, 0, 0, 0.5);\n            z-index: 1000;\n            align-items: center;\n            justify-content: center;\n        }\n\n        .remark-modal.active {\n            display: flex;\n        }\n\n        .remark-modal-content {\n            background-color: #fff;\n            width: 80%;\n            max-width: 400px;\n            border-radius: 12px;\n            padding: 20px;\n            animation: modalSlideIn 0.3s ease;\n        }\n\n        .remark-modal-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 15px;\n            padding-bottom: 10px;\n            border-bottom: 1px solid #e6e6e6;\n        }\n\n        .remark-modal-title {\n            font-size: 14px;\n            font-weight: 600;\n        }\n\n        .remark-modal-close {\n            background: none;\n            border: none;\n            font-size: 16px;\n            cursor: pointer;\n            color: #999;\n            transition: color 0.3s;\n        }\n\n        .remark-modal-close:hover {\n            color: #333;\n        }\n\n        .remark-modal-input {\n            width: 100%;\n            padding: 12px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            font-size: 12px;\n            margin-bottom: 15px;\n            transition: border-color 0.3s;\n        }\n\n        .remark-modal-input:focus {\n            outline: none;\n            border-color: var(--btn-active-color);\n        }\n\n        .remark-modal-actions {\n            display: flex;\n            justify-content: flex-end;\n            gap: 10px;\n        }\n\n        .remark-modal-cancel {\n            background: none;\n            border: 1px solid #ddd;\n            padding: 10px 20px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 12px;\n            transition: all 0.3s;\n        }\n\n        .remark-modal-cancel:hover {\n            background-color: #f5f5f5;\n        }\n\n        .remark-modal-confirm {\n            background-color: var(--btn-active-color);\n            color: var(--btn-text-color);\n            border: none;\n            padding: 10px 20px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 12px;\n            transition: background-color 0.3s;\n        }\n\n        .remark-modal-confirm:hover {\n            background-color: var(--btn-hover-color);\n        }\n\n        \/* 响应式设计 *\/\n        @media (max-width: 480px) {\n            .container {\n                max-width: 100%;\n            }\n            \n            .subscribe-action {\n                width: 12px;\n                height: 12px;\n                font-size: 10px;\n            }\n        }\n\n        @media (max-width: 360px) {\n            .subscribe-actions {\n                gap: 3px;\n            }\n            \n            .subscribe-action {\n                width: 12px;\n                height: 12px;\n                font-size: 10px;\n                padding: 4px;\n            }\n        }",
    "style": ".tag {display: inline-block;  background: #f1f1f1; color: #333333; border-radius: 15px; padding: 2px 10px; margin: 4px; box-shadow: 0 3px 6px rgba(0,0,0,0.1); transition: all 0.2s ease; cursor: pointer; } \n.post-container {\n        max-width: 800px;\n        margin: 0 auto;\n        padding: 20px;      \n        line-height: 1.6;\n        color: #333;\n    }\n    .title-card{    \t\n    border-radius: 8px;\n    text-align: center;\n    margin: 5px auto;\n    margin-bottom:20px;\n    max-width: 80%;\n    \t}\n    .post-content {\n        margin-bottom: 20px;\n    }\n    \n    .post-content p {\n        margin: 0 0 10px 0;\n        text-indent:1.7em;\n        word-break: break-word;\n    }\n    \n    .image-container {\n    position: relative;\n    display: inline-block;\n    margin: 15px 0;\n    text-align: center;\n    width: 100%;\n    min-height: 80px; \/* 给加载中提示预留高度 *\/\n}\n\n.image-container img {\n    max-width: 100%;\n    border-radius: 8px;\n    box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n    width: 100%;\n    height: auto;\n    opacity: 0;\n    transition: opacity 0.3s;\n}\n\n.image-container img.loaded {\n    opacity: 1;\n}\n\n.loading-spinner {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    background: #f5f5f5;\n    color: #666;\n    font-size: 14px;\n}\n",
    "type": 0
}
广告