📖 微博超话
https://m.weibo.cn#微博超话
分享者: guaner001125 (317)发布时间: 1天前
修小bug
{ "articleStyle": 2, "customOrder": -103, "enableJs": true, "enabled": true, "enabledCookieJar": true, "injectJs": "var wrapElements = document.querySelectorAll('div.wrap');\nvar adWrapElements = document.getElementsByClassName('ad-wrap');\n\nfor (var i = 0; i < wrapElements.length; i++) {\n var wrapElement = wrapElements[i];\n wrapElement.parentNode.removeChild(wrapElement);\n}\n\nwhile (adWrapElements.length > 0) {\n var adWrapElement = adWrapElements[0];\n adWrapElement.parentNode.removeChild(adWrapElement);\n}\n\nlet aaaa = window.location.href;\n\nif(\/\\\/a\\\/\\d+\/.test(aaaa)){\n\twindow.location.href = window.location.href.replace(\/a\/,'detail')\n\t}\n\n\nif(\/ttarticle\/.test(aaaa)){\n\nfunction styleExtractedContent() {\n \n const originalContent = document.querySelector(\".main_editor\").innerHTML.replace(\/style=\"opacity.*?\"| \/g,'').replace(\/<br>\/g,'<br>  ');\n document.body.innerHTML = '';\n \n const styledContainer = document.createElement('div');\n styledContainer.className = 'styled-article';\n \n \n styledContainer.innerHTML = originalContent;\n \n \n \n document.body.appendChild(styledContainer);\n \n \n const style = document.createElement('style');\n style.textContent = `\n .styled-article {\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n font-family: \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif;\n line-height: 1.8;\n color: #333;\n background: #fff;\n }\n \n .styled-article .title {\n font-size: 24px;\n font-weight: bold;\n margin-bottom: 20px;\n color: #222;\n text-align: center;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n }\n \n .styled-article .authorinfo {\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 #f5f5f5;\n }\n \n .styled-article .W_face_radius {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n margin-right: 10px;\n vertical-align: middle;\n }\n \n .styled-article .author1 a {\n font-size: 16px;\n color: #333;\n text-decoration: none;\n }\n \n .styled-article .time {\n color: #999;\n font-size: 14px;\n }\n \n .styled-article .preface_v2 {\n font-style: italic;\n color: #666;\n margin-bottom: 25px;\n padding: 15px;\n background: #f9f9f9;\n border-left: 3px solid #ddd;\n }\n \n .styled-article *[node-type=\"contentBody\"] p {\n margin-bottom: 25px;\n text-align: justify;\n font-size: 16px;\n color: #222; \n text-indent: 1.7em; \n }\n \n .styled-article .artical_add_box {\n margin-top: 40px;\n padding: 20px;\n background: #fafafa;\n border-radius: 8px;\n }\n \n .styled-article .btn_bed a {\n display: inline-block;\n padding: 8px 15px;\n background: #ff8200;\n color: white;\n border-radius: 4px;\n text-decoration: none;\n }\n \n \n @media (max-width: 600px) {\n .styled-article {\n padding: 15px;\n }\n \n .styled-article .title {\n font-size: 20px;\n }\n \n .styled-article .WB_editor_iframe_new p {\n font-size: 15px;\n }\n }\n `;\n \n document.head.appendChild(style);\n}\n\n\nstyleExtractedContent();\n\n\n\t\n\t\n\t}", "jsLib": "function getHeaderMap(_){\n\t const { source,java } = _ || this;\n let infomap = String(source.getLoginHeader()).replace(\/^#\/,'');\n infomap = (infomap!=\"null\"&&infomap!=\"\"&&infomap!=null)?infomap:\"{}\";\n return JSON.parse(infomap);\n\t}\n\nfunction setHeaders(){\n \tconst { source,java } = this;\n \tlet map = getHeaderMap(this);\n \tfor(let i=0;i<arguments.length;i++){\n \t\tlet k =arguments[i].split(\"=\")[0];\n \t\tlet v =arguments[i].split(\"=\")[1];\n \t\tmap[k] = v;\n \t\t}\n source.putLoginHeader(\"#\"+JSON.stringify(map))\n\t}\n\t\nfunction Map(e,that) { \n\t const { source } = that || this;\n return getHeaderMap(that||this)[e]??\"\"\n}", "lastUpdateTime": 0, "loadWithBaseUrl": true, "loginUi": "[\n{\n \t name:\"☕️支持源作者\",\n \t type: \"button\",\n action: \"toThank()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n \t},\n \t{\n \t name:\"👤登 录\",\n \t type: \"button\",\n action: \"toLogin()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n \t}\n]", "loginUrl": "function toThank(){\n\tjava.startBrowser(\"data:text\/html;base64,PGltZyBzdHlsZT0id2lkdGg6MTAwJSIgc3JjPSJhYm91dDpibGFuayIgb25lcnJvcj0idGhpcy5zcmM9YXRvYignYUhSMGNITTZMeTluYVhSbFpTNWpiMjB2WjNWaGJtVnlNREF4TVRJMUwySnZiMnR6YjNWeVkyVXZjbUYzTDIxaGMzUmxjaThsUlRVbE9VSWxRa1VsUlRjbE9Ea2xPRGN2WjNWaGJtVnlMbmRsWW5BPScpIj4KCg==\",\"感谢你的支持\");\t\n\t}\nfunction toLogin(){\n\tjava.startBrowser(\"https:\/\/weibo.com\",\"登录\");\n\tjava.startBrowser(\"http:\/\/m.weibo.cn\",\"登录\")\n\t\n\t}", "ruleArticles": "<js>\njava.put(\"src\",result);\nlet search = String(source.getVariable());\nlet f = \/page_type=searchall\/.test(baseUrl);\nlet baseUrl = String(f?baseUrl:java.hexDecodeToString(result));\npage = baseUrl.match(\/page=([^;]+)\/)?.[1];\nid = baseUrl.match(\/containerid=([^_]+)\/)?.[1];\ncontainerid =Map(id);\nif(!\/feed\/.test(containerid)&&containerid!==\"\"){\t\n\tbaseUrl = `https:\/\/m.weibo.cn\/api\/container\/getIndex?containerid=${containerid}&since_id=${page==1?\"\":page}`;\n\t}\n\nif(search!==\"\"&search!==\"null\"&&!f&&\/feed\/.test(containerid||\"feed\")){\n\turl = `https:\/\/m.weibo.cn\/api\/container\/getIndex?extparam=%7B%22topicid%22%3A%221022%3A${id}%22%2C%22pagetype%22%3A%22index%22%7D&container_ext=type%3A532%7Cdisable_history%3A1%7Ccache_need%3A0%7Cforce_ejecttype%3Apresent&containerid=100303type%3D532%26q%3D${search}%26t%3D0&page=${page}&count=10&new_topic_header_recommend=1&new_topic_header=1&page_type=searchall`;\n\tresult = java.ajax(url)\n\t}else if(!f){\n\t\tresult = java.ajax(baseUrl);\n\t\t}\njava.setContent(result);\nif(containerid){java.put(\"since_id\",java.getString(\"$.data.pageInfo.since_id\"))}\nresult = String(result).replace(\/\"(name|containerid)\"\/g,'\"$1test\"');\n<\/js>\n$.data.cards&&$.data.cards[*].card_group[*]&&data.cards[*].card_group[*].pics[*]&&data.cards[*].card_group[*].items[*]\n<js>\nif(\/page=1\/.test(baseUrl)){\n\t\t\tresult = JSON.stringify(java.getElements(\"$..[?(@.channel_list)]&&$..[?(@.card_type==121)]\").toArray().concat(result.toArray()));\n\t}\t\njava.setContent(java.get(\"src\"))\nresult\n<\/js>\n$.[*]", "ruleContent": "@js:\nif(\/containeridhtml\/.test(baseUrl)){\n\t\n\tlet text = String(java.hexDecodeToString(result));\n\tlet cid = text.match(\/=([^_]+)\/)[1];\n\tlet m = String(java.hexDecodeToString(java.get(\"src\"))).match(\/containerid=([^&]+)\/)?.[1];\n\tlet html = `\n<html>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n<meta charset=\"UTF-8\">\n<html>\n<head>\n <style>\n .button-container {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n padding: 20px;\n } \n .button {\n padding: 10px 15px;\n background-color: #4CAF50;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.3s ease;\n }\n \n .button.active {\n background-color: #f44336;\n transform: scale(1.05);\n box-shadow: 0 4px 8px rgba(0,0,0,0.2);\n }\n <\/style>\n<\/head>\n<body>\n选择完点“✓”\n <div class=\"button-container\" id=\"buttons\"><button class=\"button ${Map(cid)?\"\":\"active\"}\" data-value=\"${m}\" onclick=\"setActiveButton(this)\">首页<\/button><\/div>\n\n <script>\n const inputString = \"${text.replace(\/&$\/,'')}\";\n \n const pairs = inputString.split('&');\n const buttonContainer = document.getElementById('buttons');\n let buttons = [];\n buttons.push(document.querySelector(\".button\"))\n pairs.forEach(pair => {\n const [buttonText, buttonValue] = pair.split('=');\n \n const button = document.createElement('button');\n button.className = 'button';\n button.textContent = buttonText;\n button.dataset.value = buttonValue; \n buttons.push(button);\n \n button.addEventListener('click', function() {\n setActiveButton(this);\n });\n \n buttonContainer.appendChild(button);\n });\n\n \n function setActiveButton(targetButton) {\n buttons.forEach(button => {\n button.classList.remove('active');\n });\n targetButton.classList.add('active');\n }\n\n function setActiveByValue() {\n const valueToFind = \"${Map(cid)}\"\n if (!valueToFind) return;\n const targetButton = buttons.find(button => \n button.dataset.value === valueToFind\n );\n if (targetButton) {\n setActiveButton(targetButton);\n } \n }\n setActiveByValue()\n <\/script>\n<\/body>\n<\/html>\n`;\nlet select;\ntry{\nselect = java.startBrowserAwait(`data:text\/html;base64,${java.base64Encode(html)}`,\"选择tab\",false).body();\nlet all = String(java.getString(\"@class.active.0@data-value\",select));\nlet id = all.match(\/^([^_]+)\/)?.[1];\nsetHeaders(id+\"=\"+all);\nresult = \"已选择完成,返回超话刷新\"\n}catch(e){\"未选择或是之前的缓存,点右上角的🔄刷新可进入选择tab页面\"}\n\t}else if(!\/large\/.test(baseUrl)){\nfunction formatTime(dateStr) {\n const date = new Date(dateStr);\n const year = date.getFullYear();\n const month = date.getMonth() + 1; \n const day = date.getDate();\n const hours = date.getHours().toString().padStart(2, '0');\n const minutes = date.getMinutes().toString().padStart(2, '0');\n \n return `${year}年${month}月${day}日 ${hours}:${minutes}`;\n}\nfunction formatCount(count) {\n if (count < 10000) return count.toString(); \n const inWan = (count \/ 10000).toFixed(2);\n return inWan.endsWith('.00') \n ? `${inWan.split('.')[0]}万` \n : `${inWan}万`;\n}\n\nfunction getContent($) {\n let galleryItems = \"\",videos=\"\";\n \n let long_imgs = ($.pic_num??0)?($.pics??[]):[];\n let long_video = $.page_info?.type===\"video\"?$.page_info:{};\n \n if(long_imgs.length){\n galleryItems = long_imgs.map((img, i) => `\n <div class=\"gallery-item\">\n <img src=\"${img.url}\" data-original=\"${img?.large?.url}\" loading=\"lazy\">\n <div class=\"zoom-icon\">🔍<\/div>\n <\/div>`).join('');\n galleryItems = `<div class=\"image-gallery\">${galleryItems}<\/div>`;\n }\n if(JSON.stringify(long_video)!==\"{}\"){\n if(long_video.urls){\n long_video = long_video.urls;\n videos = long_video.hevc_mp4_hd || long_video.mp4_720p_mp4 || long_video.mp4_hd_mp4 || long_video.mp4_ld_mp4\n }else{\n long_video = long_video.media_info;\n videos = long_video.stream_url_hd || long_video.stream_url\n }\n \n videos = `<div class=\"media-container\"><video src=\"${videos}\" controls poster=\"${$.page_info.page_pic.url}\"><\/video><\/div>`\n }\n \n return `\n <div class=\"comment-item\">\n <div class=\"comment-user\">\n <img class=\"user-avatar\" src=\"${$.user.profile_image_url}\">\n <div class=\"user-info\">\n <span class=\"user-name\">${$.user.screen_name}<\/span>\n <span class=\"comment-time\">${formatTime($.created_at)}<\/span>\n <\/div>\n <div class=\"like_counts\"><span>♡${formatCount($.attitudes_count)}<\/span><\/div>\n <\/div>\n <div class=\"comment-text\">${$.text}<\/div>\n ${videos}\n ${galleryItems}\n <\/div>`;\n}\n\nlet id = baseUrl.match(\/(\\d+)\/)[1];\nlet b = baseUrl.replace(\/weibo.com\/,'m.weibo.cn');\nvar html = java.ajax(b);\n\nvar render_data = html.match(\/var \\$(render_data = \\[\\{[\\s\\S]+?\\|\\| \\{\\});\/)[1];\neval(render_data);\nlet $ = render_data.status;\n\n\nlet longText = getContent($);\n\n\nlet retweeted_status = $.retweeted_status??\"\";\nif(retweeted_status){\n retweeted_status = getContent(retweeted_status)\n}\n\nretweeted_status = retweeted_status ? \"<div class='retweeted_status'>\" + retweeted_status+\"<\/div>\":\"\";\nresult = longText + retweeted_status;\n\nresult = `<a href=\"${b.replace(\/detail\/,'a')}\" class=\"original-link\">原文地址<\/a><div class=\"main-content\">${result}<\/div><div id=\"container\"><\/div>`;\n\nresult = `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n \n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>微博详情<\/title>\n <link rel=\"stylesheet\" href=\"https:\/\/cdn.jsdelivr.net\/npm\/viewerjs@1.10.5\/dist\/viewer.min.css\">\n <style> \n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { \n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif; \n line-height: 1.6; color: #333; background-color: #f5f5f5; \n padding: 15px; max-width: 750px; margin: 0 auto; \n }\n .original-link { \n display: block; padding: 12px; background: #fff; border-radius: 8px; \n margin-bottom: 10px; text-decoration: none; color: #1E88E5; \n font-weight: 500; box-shadow: 0 1px 3px rgba(0,0,0,0.05); \n }\n .main-content { \n background: #fff; padding: 15px; border-radius: 8px; \n margin-bottom: 15px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); \n }\n .divider { border: none; height: 1px; background-color: #eee; margin: 15px 0; }\n .media-container { margin: 15px 0; border-radius: 8px; overflow: hidden; }\n .media-container video { width: 100%; border-radius: 8px; }\n .image-gallery { \n display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; margin: 15px 0; \n max-width:100%\n }\n .gallery-item { \n aspect-ratio: 1; overflow: hidden; border-radius: 8px; \n position: relative; cursor: pointer; \n }\n .gallery-item img { \n width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s; \n }\n .gallery-item:hover img { transform: scale(1.05); }\n .zoom-icon { \n position: absolute; top: 5px; right: 5px; background: rgba(0,0,0,0.5); \n color: white; width: 20px; height: 20px; border-radius: 50%; \n display: flex; align-items: center; justify-content: center; \n font-size: 12px; opacity: 0; transition: opacity 0.3s; \n }\n .retweeted_status{\n background:#ECECEC;\n padding:15px;\n border-radius:8px;\n }\n .gallery-item:hover .zoom-icon { opacity: 1; }\n .comments-section { \n background: #fff; padding: 15px; border-radius: 8px; \n box-shadow: 0 1px 3px rgba(0,0,0,0.05); \n }\n .comment-replies{\n \tbackground:#efefef;\n \tpadding:5px 5px 5px 20px;\n \tmargin-left:42px;\n \tborder-radius: 8px;\n \tbox-shadow: 0 1px 3px rgba(0,0,0,0.05);\n \t\n \t}\n \t\n.comments-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom:10px\n}\n\n.comments-title {\n margin: 0;\n font-size: 18px; \n color: #333; \n}\n\n.sort-controls {\n display: flex;\n align-items: center;\n}\n\n.sort-btn {\n padding: 4px 12px;\n border: 1px solid #e0e0e0;\n background: #f5f5f5;\n border-radius: 15px;\n font-size: 12px;\n cursor: pointer;\n margin-right: 8px; \n transition: all 0.3s;\n}\n\n\n.sort-btn:last-child {\n margin-right: 0;\n}\n\n.sort-btn.active {\n background: #1d9bf0;\n color: white;\n border-color: #1d9bf0;\n}\n\n \n .comment-item { padding: 12px 0; }\n \n .comment-user { display: flex; align-items: flex-start; margin-bottom: 8px; }\n .user-avatar { \n width: 32px; height: 32px; border-radius: 50%; \n margin-right: 10px; object-fit: cover; \n }\n .user-info {\n display: flex;\n flex-direction: column;\n}\n .user-name { \n font-weight: 500; \n font-size: 15px;\n color:#1E88E5\n }\n .comment-text { \n margin-left: 42px;\n margin-bottom: 8px; font-size: 15px; line-height: 1.5; word-break: break-word; \n }\n .comment-time { font-size: 12px; color: #999; }\n .comment-media { \n margin-left:42px;\n margin-bottom:10px;\n margin-top:10px;\n margin-right:8px;\n position: relative; cursor: pointer; \n border-radius: 6px; overflow: hidden;\n max-width:100%\n }\n .comment-media details {\n margin: 8px 0;\n border-radius: 6px;\n overflow: hidden;\n }\n .comment-media summary {\n padding: 6px 12px;\n background: #f5f5f5;\n border-radius: 4px;\n cursor: pointer;\n list-style: none;\n font-size: 14px;\n color: #1E88E5;\n transition: background 0.2s;\n }\n .comment-media summary:hover {\n background: #e8f0fe;\n }\n .comment-media summary::-webkit-details-marker {\n display: none;\n }\n .comment-media div {\n margin-top: 8px;\n position: relative;\n cursor: pointer;\n }\n .comment-media img {\n max-width: 100%;\n border-radius: 4px;\n display: block;\n }\n.active {\n pointer-events: none; \n}\n\n .float-buttons {\n position: fixed;\n right: 20px;\n bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n z-index: 1001;\n }\n .reply-modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 1000;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.modal-content {\n width: 80%;\n max-width: 600px;\n max-height: 80vh;\n background: white;\n border-radius: 8px;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.modal-body {\n flex: 1;\n overflow-y: auto;\n padding: 15px;\n}\n.modal-footer {\n padding: 10px;\n text-align: center;\n}\n.loading-spinner {\n display: none;\n width: 20px;\n height: 20px;\n border: 3px solid rgba(0,0,0,0.1);\n border-radius: 50%;\n border-top-color: #1d9bf0;\n animation: spin 1s linear infinite;\n margin: 0 auto;\n}\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n.reply-sort {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n.close-btn {\n cursor: pointer;\n font-size: 20px;\n}\n.like_counts{\ncolor:#999;\nfont-size:12px;\nmargin-left:auto;\npadding-right:8px\n}\n .float-btn {\n width: 25px;\n height: 25px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.5);\n color: white;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 15px;\n transition: all 0.3s ease;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n -webkit-tap-highlight-color: transparent !important;\n tap-highlight-color: transparent !importan;\n outline: none !important;\n -webkit-tap-highlight-color: transparent !important;\n }\n \n.float-btn:focus,\n.float-btn:focus-visible,\n.float-btn:active,\n.float-btn:-moz-focusring {\n outline: none !important;\n box-shadow: none !important;\n}\n.morerep{\ntext-align:right;\ncolor:#4590B5;\nfont-size:13px\n}\n .float-btn:hover {\n background: rgba(0, 0, 0, 0.7);\n transform: scale(1.1);\n }\n .error-message{\n \tbackground:#eee;\n padding:15px;\n font-size:18px;\n \t}\n\n .media-preview::before {\n content: \"⬇️ \";\n }\n .comment-media[open] summary .media-preview::before {\n content: \"⬆️ \";\n }\n .url-icon img { vertical-align: middle; margin: 0 1px;width:1em; height:1em}\n .surl-text { color: #1E88E5; margin-right: 5px; }\n @media (max-width: 500px) {\n .image-gallery { grid-template-columns: repeat(2, 1fr); }\n body { padding: 10px; }\n .main-content, .comments-section { padding: 12px; }\n } \n \n .viewer-open {\n overflow: hidden;\n position: fixed;\n width: 100%;\n }\n <\/style>\n <script>\n function formatTime(dateStr) {\n const date = new Date(dateStr);\n const year = date.getFullYear();\n const month = date.getMonth() + 1; const day = date.getDate();\n const hours = date.getHours().toString().padStart(2, '0');\n const minutes = date.getMinutes().toString().padStart(2, '0');\n \n return \\`\\${year}年\\${month}月\\${day}日 \\${hours}:\\${minutes}\\`;\n}\n function getcomments(list, isReply = false) {\n return list.map(item => {\n let details = \"\";\n if (item.pic_num !== 0) {\n let pic_ids = item.url_struct[0].pic_ids; \n const pic = item?.url_struct[0]?.pic_infos[pic_ids]?.large?.url.replace(\/https?\/,'https');\n details = \\`\n <details class=\"comment-media\">\n <summary><span class=\"media-preview\">📷 查看图片<\/span><\/summary>\n <div class=\"comment_pic\">\n <img src=\"\\${pic}\" alt=\"评论图片\">\n <\/div>\n <\/details>\\`;\n }\n \n let replies = \"\";\n if (item.comments && item.comments.length > 0) {\n replies = \\`\n <div class=\"comment-replies\">\n \\${getcomments(item.comments, true)}\n \\${item.total_number > 1 ? \\`\n <div class=\"morerep\" onclick=\"loadComments({id:'\\${item.id}',isReply:true})\">\n 共\\${item.total_number}条回复\n <\/div>\\` : ''}\n <\/div>\\`;\n }\n \n return \\`\n <div class=\"comment-item\">\n <div class=\"comment-user\">\n <img class=\"user-avatar\" src=\"\\${item.user.profile_image_url}\">\n <div class=\"user-info\">\n <span class=\"user-name\">\\${item.user.screen_name}<\/span>\n <span class=\"comment-time\">\\${formatTime(item.created_at)}<\/span>\n <\/div>\n <div class=\"like_counts\"><span>♡\\${formatCount(item.like_counts)}<\/span><\/div>\n <\/div>\n <div class=\"comment-text\">\\${item.text.replace(\/(<img.*?>)\/g,'<span class=\"url-icon\">$1<\/span>')}<\/div>\n \\${details}\n \\${replies}\n <\/div>\\`;\n }).join('');\n}\n <\/script>\n \n<\/head>\n<body>\n ${result}\n <div class=\"float-buttons\">\n <button class=\"float-btn\" id=\"toTop\" title=\"回到顶部\">↑<\/button>\n <button class=\"float-btn\" id=\"toBottom\" title=\"回到底部\">↓<\/button>\n <\/div>\n <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/viewerjs@1.10.5\/dist\/viewer.min.js\"><\/script>\n <script>\n \/\/ 全局变量\n let MaxId = []; \n let repMaxId = []; \n let currentMaxId = null;\n let repCurrentMaxId = null;\n let isLoading = false;\n let repLoading = false;\n const weiboId = \"${id}\";\n let sortType = 0;\n let repSortType = 0;\n \n function formatCount(count) {\n if (count < 10000) return count.toString(); \n const inWan = (count \/ 10000).toFixed(2);\n return inWan.endsWith('.00') \n ? \\`\\${inWan.split('.')[0]}万\\` \n : \\`\\${inWan}万\\`;\n}\n\n \/\/图片加载器\n function initImageViewer() {\n \tvar option = {\n \t\t url: 'data-original',\n \t \tmaxZoomRatio: 0.9,\n inline: false,\n movable: true,\n zoomable: true,\n \n toolbar: {\n zoomIn: 1,\n zoomOut: 1,\n oneToOne: 0,\n reset: 1,\n prev: 1,\n next: 1,\n rotateLeft: 0,\n rotateRight: 0,\n flipHorizontal: 0,\n flipVertical: 0\n } \n }; \n try { \n new Viewer(document.querySelector('.image-gallery'),option); \n document.querySelectorAll('.comment-media').forEach(x=>{new Viewer(x,option)}) \n } catch (e) {\n \n }\n \n }\n \n\/\/ 获取评论函数\nasync function loadComments(options = {}) {\n const {\n id = weiboId,\n isReply = false,\n isLoadMore = false,\n targetElement = isReply ? '#reply-list' : '#container',\n tElement = isReply ? '#reply-list .comments-list' : '.comments-list',\n containerTemplate = null,\n sort = isReply ? repSortType : sortType\n } = options;\n\n \n const loadingFlag = isReply ? repLoading : isLoading;\n if (loadingFlag) return;\n isReply ? repLoading = true : isLoading = true;\n\n \n let url;\n if (isReply) {\n url = \\`https:\/\/weibo.com\/ajax\/statuses\/buildComments?flow=\\${sort}&is_reload=1&id=\\${id}&is_show_bulletin=2&is_mix=1&fetch_level=1&max_id=\\${isLoadMore ? repCurrentMaxId : 0}&count=20&locale=zh-CN\\`\n } else {\n url =\\`https:\/\/weibo.com\/ajax\/statuses\/buildComments?flow=\\${sort}&is_reload=1&id=\\${id}&is_show_bulletin=2&is_mix=0&count=20&fetch_level=0&locale=zh-CN\\`;\n \n \n \/\/url = \\`https:\/\/m.weibo.cn\/comments\/hotflow?id=\\${id}&mid=\\${id}&max_id_type=\\${sort}\\`;\n if (isLoadMore && currentMaxId) {\n url += \\`&max_id=\\${currentMaxId}\\`;\n }\n }\n\n try {\n const response = await fetch(url, {\n headers: {\n 'Accept': 'application\/json',\n 'X-Requested-With': 'XMLHttpRequest'\n },\n credentials: 'include'\n });\n\n const data = await response.json();\n \n \n if (data.ok === -100) {\n if (\/error-message\/.test(document.querySelector(targetElement).innerHTML)) {\n throw new Error(\"需要登录\");\n }\n document.querySelector(targetElement).innerHTML += \\`\n <div class=\"error-message\">\n 评论加载失败:请<a href=\"\\${data.url}\">访问首页或登录<\/a>后重试\n <\/div>\n \\`;\n throw new Error(\"需登录\");\n }\n\n \n const currentIdArray = isReply ? repMaxId : MaxId;\n const newMaxId = data.max_id;\n \n if (currentIdArray.includes(newMaxId)) {\n throw new Error(\"没有更多内容了\");\n }\n \n if (isReply) {\n repCurrentMaxId = newMaxId;\n repMaxId.push(newMaxId);\n } else {\n currentMaxId = newMaxId;\n MaxId.push(newMaxId);\n }\n \n \n const commentsData = data.data;\n \n if (isReply && !isLoadMore && !document.querySelector('.reply-modal')) {\n initReplyModal(id);\n }\n\n if (isLoadMore) {\n document.querySelector(tElement).innerHTML += getcomments(commentsData, isReply);\n } else {\n if (data.ok === 0) throw new Error(\"没有内容\");\n \n \n let content = \\`<div class=\"comments-header\">\n <div class=\"comments-title\"><h3>评论(\\${formatCount(data.total_number)})<\/h3><\/div>\n <div class=\"sort-controls\">\n <button id=\"sortHot\" class=\"sort-btn \\${sortType===0?'active':''}\" \n onclick=\"loadComments({sort:0})\">热度<\/button>\n <button id=\"sortTime\" class=\"sort-btn \\${sortType===1?'active':''}\" \n onclick=\"loadComments({sort:1})\">时间<\/button>\n <\/div>\n <\/div>\\`;\n \n const html = \\`\n <div class=\"comments-section\">\n \\${isReply?\"\":content} \n <div class=\"comments-list\">\\${getcomments(commentsData)}<\/div>\n <\/div>\n \\`;\n document.querySelector(targetElement).innerHTML = html;\n }\n\n\n } catch (error) {\n if (isLoadMore) {\n showToast(\/没有更多\/.test(error.message)?error.message:\"评论加载失败\")\n } else if (!\/没有内容|登录\/.test(error.message)) {\n document.querySelector(targetElement).innerHTML = \\`\n <div class=\"error-message\">\n 评论加载失败: \\${error.message}\n <button onclick=\"loadComments(\\${JSON.stringify(options)})\">重试<\/button>\n <\/div>\n \\`;\n }\n } finally {\n isReply ? repLoading = false : isLoading = false;\n }\n}\n\n\nfunction initReplyModal(id) {\n const modal = document.createElement('div');\n modal.className = 'reply-modal';\n modal.dataset.commentId = id;\n modal.innerHTML = \\`\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h4>回复列表<\/h4>\n <div class=\"reply-sort\">\n <button class=\"sort-btn \\${repSortType===0?'active':''}\" \n onclick=\"loadComments({id:'\\${id}',isReply:true,sort:0});repSortType=0\" data-sort-type=0>热度<\/button>\n <button class=\"sort-btn \\${repSortType===1?'active':''}\" \n onclick=\"loadComments({id:'\\${id}',isReply:true,sort:1});repSortType=1\" data-sort-type=1>时间<\/button>\n <span class=\"close-btn\" onclick=\"this.closest('.reply-modal').remove();repMaxId=[];repSortType=0;repCurrentMaxId=null\">×<\/span>\n <\/div>\n <\/div>\n <div class=\"modal-body\" id=\"reply-list\"><\/div>\n <\/div>\n \\`;\n document.body.appendChild(modal);\n modal.addEventListener('click', function(e) {\n \n if (e.target === modal) {\n modal.remove();\n repMaxId = [];\n repSortType = 0;\n repCurrentMaxId = null;\n }\n});\n\n \n const replyList = document.querySelector(\"#reply-list\");\nif (replyList) {\n replyList.addEventListener('scroll', () => {\n if (replyList.scrollTop + replyList.clientHeight >= replyList.scrollHeight - 15) {\n loadComments({id:id,isLoadMore: true, isReply: true }); \n }\n });\n}\n \n}\n\n\nfunction showToast(message) {\n const toast = document.createElement('div');\n toast.textContent = message;\n toast.style.position = 'fixed';\n toast.style.bottom = '50px';\n toast.style.left = '50%';\n toast.style.transform = 'translateX(-50%)';\n toast.style.backgroundColor = 'rgba(0,0,0,0.7)';\n toast.style.color = 'white';\n toast.style.padding = '5px 5px';\n toast.style.borderRadius = '5px';\n toast.style.zIndex = '1000';\n \n document.body.appendChild(toast);\n setTimeout(() => {\n document.body.removeChild(toast);\n }, 1000);\n}\n\ndocument.getElementById('toTop').addEventListener('click', function() {\n if(document.querySelector(\"#reply-list\")){\n document.querySelector(\"#reply-list\").scrollTo({\n top: 0,\n behavior: 'smooth'\n });\n }else{\n window.scrollTo({\n top: 0,\n behavior: 'smooth'\n });\n }\n \n });\n \n document.getElementById('toBottom').addEventListener('click', function() {\n if(document.querySelector(\"#reply-list\")){\n document.querySelector(\"#reply-list\").scrollTo({\n top: document.querySelector(\"#reply-list\").scrollHeight,\n behavior: 'smooth'\n });\n }else{\n window.scrollTo({\n top: document.body.scrollHeight,\n behavior: 'smooth'\n });\n }\n });\n \n \n window.addEventListener('scroll', function() {\n const toTopBtn = document.getElementById('toTop');\n const toBottomBtn = document.getElementById('toBottom');\n const scrollPosition = window.scrollY;\n \n \n if (scrollPosition === 0) {\n toTopBtn.style.opacity = '0.5';\n toTopBtn.style.pointerEvents = 'none';\n } else {\n toTopBtn.style.opacity = '1';\n toTopBtn.style.pointerEvents = 'auto';\n }\n \n \n if (window.innerHeight + scrollPosition >= document.body.scrollHeight - 50) {\n toBottomBtn.style.opacity = '0.5';\n toBottomBtn.style.pointerEvents = 'none';\n } else {\n toBottomBtn.style.opacity = '1';\n toBottomBtn.style.pointerEvents = 'auto';\n }\n });\n\n\n\n\n\n\ndocument.addEventListener('DOMContentLoaded', () => {\n \n document.addEventListener('click', (e) => {\n \n if (e.target.id === 'sortHot') {\n if (sortType !== 0) {\n sortType = 0;\n e.target.classList.add('active');\n document.getElementById('sortTime').classList.remove('active');\n currentMaxId = null;\n MaxId = [];\n loadComments({sort:0}); \n }\n }\n \n if (e.target.id === 'sortTime') {\n if (sortType !== 1) {\n sortType = 1;\n e.target.classList.add('active');\n document.getElementById('sortHot').classList.remove('active');\n currentMaxId = null;\n MaxId = [];\n loadComments({sort:1}); \n }\n }\n\n \n if (e.target.classList.contains('sort-btn')) {\n const modal = e.target.closest('.reply-modal');\n if (modal) {\n const id = modal.dataset.commentId;\n repSortType = parseInt(e.target.dataset.sortType);\n \n document.querySelectorAll('.reply-modal .sort-btn').forEach(btn => {\n btn.classList.toggle('active', parseInt(btn.dataset.sortType) === repSortType);\n });\n repCurrentMaxId = null;\n repMaxId = [];\n }\n }\n });\n \n \n loadComments();\n \n \n window.addEventListener('scroll', () => {\n if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 50) {\n loadComments({ isLoadMore: true });\n }\n });\n \n function findScrollingElement() {\n const elements = document.querySelectorAll('*');\n for (const el of elements) {\n if (el.scrollHeight > el.clientHeight && el.scrollTop > 0) {\n return el;\n }\n }\n return document.documentElement; \n}\n\n\n \n \n \n initImageViewer();\n});\n \n <\/script>\n<\/body>\n<\/html>`;\n\nresult;\n\n}else{\n\t\"<img src=\\\"\"+baseUrl+\"\\\">\"\n\t}\n", "ruleDescription": "$.scheme\n<js>\nif(\/containerid\/.test(result)){\n\tlet id = result.match(\/containerid=(.*)\/)[1];\n\tlet pic = java.getString(\"$.pic\");\n\tlet title_sub = java.getString(\"$.title_sub\");\n\tlet desc1 = java.getString(\"$.desc1\");\n\tlet intro = java.getString(\"$.desc2\");\n\tlet copytext = `${title_sub}::data:page=1;base64,{\\{java.base64Encode(\"https:\/\/m.weibo.cn\/api\/container\/getIndex?containerid=${id}_-_feed&page=1\")}},{\"type\":\"\"}`;\n\tresult = `<div class=\"container\">\n <div class=\"content-row\">\n <!-- 左侧图片 (固定80px) -->\n <div class=\"image-box\">\n <img src=\"${pic}\" class=\"fixed-image\" alt=\"${title_sub}\">\n <\/div>\n \n <!-- 右侧文字区域 -->\n <div class=\"text-box\">\n <div class=\"intro-line\">${intro}<\/div>\n <div class=\"desc-scroll-box\">\n <div class=\"desc-line\">${desc1}<\/div>\n <\/div>\n <\/div>\n <\/div>\n \n <!-- 底部复制区域 -->\n <div class=\"copy-area\">\n <div class=\"copy-text\" id=\"copyContent\">${copytext}<\/div>\n <button class=\"copy-button\" onclick=\"handleCopy()\">\n <span class=\"icon\">⎘<\/span>\n <span>一键复制链接后粘贴至分类URL<\/span>\n <\/button>\n <div class=\"copy-message\" id=\"copyFeedback\"><\/div>\n <\/div>\n<\/div>\n\n<style>\n .container {\n max-width: 800px;\n margin: 0 auto;\n padding: 12px;\n font-family: system-ui, sans-serif;\n }\n \n \/* 严格的左图右文布局 (不用gap) *\/\n .content-row {\n display: flex;\n align-items: flex-start;\n margin-bottom: 16px;\n }\n \n \/* 严格限制图片80px *\/\n .image-box {\n width: 80px;\n height: 80px;\n margin-right: 12px; \/* 替代gap *\/\n }\n \n .fixed-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 4px;\n }\n \n \/* 右侧文字区域 *\/\n .text-box {\n flex: 1;\n min-width: 0; \/* 防止内容溢出 *\/\n }\n \n .intro-line {\n font-size: 15px;\n line-height: 1.4;\n color: #333;\n margin-bottom: 6px;\n }\n \n \/* desc1可滚动区域 *\/\n .desc-scroll-box {\n height: 60px; \/* 固定高度 *\/\n overflow-y: auto; \/* 垂直滚动 *\/\n padding-right: 5px;\n border: 1px solid #eee;\n border-radius: 3px;\n }\n \n .desc-line {\n font-size: 13px;\n line-height: 1.4;\n color: #666;\n padding: 4px;\n white-space: pre-wrap; \/* 保留换行 *\/\n }\n \n \/* 滚动条样式 *\/\n .desc-scroll-box::-webkit-scrollbar {\n width: 4px;\n }\n \n .desc-scroll-box::-webkit-scrollbar-thumb {\n background: #ccc;\n border-radius: 2px;\n }\n \n \/* 复制区域样式 *\/\n .copy-area {\n padding: 12px;\n background: #f5f5f5;\n border-radius: 6px;\n }\n \n .copy-text {\n padding: 10px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n word-break: break-all;\n margin-bottom: 10px;\n }\n \n .copy-button {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 8px;\n background: #2196F3;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 14px;\n cursor: pointer;\n width: 100%;\n }\n \n .copy-button:hover {\n background: #0d8bf2;\n }\n \n .icon {\n margin-right: 5px;\n }\n \n .copy-message {\n height: 16px;\n margin-top: 6px;\n font-size: 12px;\n text-align: center;\n }\n<\/style>\n\n<script>\n function handleCopy() {\n const content = document.getElementById('copyContent');\n const feedback = document.getElementById('copyFeedback');\n \n const range = document.createRange();\n range.selectNode(content);\n window.getSelection().removeAllRanges();\n window.getSelection().addRange(range);\n \n try {\n const successful = document.execCommand('copy');\n feedback.textContent = successful ? '复制成功' : '请手动选择复制';\n feedback.style.color = successful ? '#4CAF50' : '#F44336';\n } catch(err) {\n feedback.textContent = '复制失败';\n feedback.style.color = '#F44336';\n }\n \n window.getSelection().removeAllRanges();\n setTimeout(() => feedback.textContent = '', 1500);\n }\n<\/script>\n`\n\t}\n<\/js>", "ruleImage": "{{$.pic_middle||$..bmiddle_pic||$..bmiddle.url||$..page_pic.url||$.mblog.page_info.page_pic.url||$.mblog.user.avatar_hd||$.avatar_hd||$.user.avatar_hd||$..avatar_hd||$.left_tag_img||$.pic##.*\\n+}},{\"headers\":{\"referer\":\"https:\/\/m.weibo.cn\"}}\n<js>##thumbnail##bmiddle<\/js>", "ruleLink": "$.pic_big||$.mblog.id||$.scheme||$..containerid\n@js:\nif(\/containerid\/.test(result)){\n\tid = result.match(\/containerid=(.*)\/)[1];\n\tresult = \"https:\/\/m.weibo.cn\/api\/container\/getIndex?containerid=\"+id;\n\t}else if(\/^\\d+$|applink\/.test(result)){\n\tresult = \/applink\/.test(result)?result.match(\/D(\\d+)\/)[1]:result;\n\tresult = \t\"https:\/\/weibo.com\/detail\/\"+result\n\t\t}else if(\/_\/.test(result)){\n\t\t\tname = java.getStringList(\"$..name\").toArray();\n\t\t\tcontainerid = java.getStringList(\"$..containerid\").toArray();\n\t\t\ttext = \"\";\n\t\t\tname.forEach((x,i)=>{\n\t\t\t\ttext+= x+\"=\"+containerid[i]+\"&\"\n\t\t\t\t});\n\t\t`data:containeridhtml${Date.now()};base64,${java.base64Encode(text)},{\"type\":\"\"}`;\n\t\t\t}else if(\/large\/.test(result)){\n\t\t\t\tresult\n\t\t\t\t}", "ruleNextPage": "@js:\nlet f =\/page_type=searchall\/.test(baseUrl);\nlet baseUrl = String(f?baseUrl:java.hexDecodeToString(result));\nsince_id = String(java.get(\"since_id\"));\nlet feed = \/feed\/.test(baseUrl);\npage = Number(baseUrl.match(\/page=(\\d+)\/)?.[1])+1;\npage = (since_id&&!feed)?since_id:page;\nbaseUrl = baseUrl.replace(\/page=\\d+\/,'page='+page);\nresult = f?baseUrl:`data:page=${page};base64,${java.base64Encode(baseUrl)},{\"type\":\"\"}`", "rulePubDate": "$.mblog.created_at\n<js>\nif(result){\ndate=new Date(result);\ntime=date.getTime();\nfunction formatDate2(inputTime) {\n var date = new Date(inputTime);\n var y = date.getFullYear();\n var m = date.getMonth() + 1;\n m = m < 10 ? ('0' + m) : m;\n var d = date.getDate();\n d = d < 10 ? ('0' + d) : d;\n return y +'-' + m + '-' + d;\n};\n\nfunction formatDate(now) {\n var time = formatDate2(now)\n var date1 = new Date(now)\n var date2 = new Date()\n var date3 = date2.getTime() - date1.getTime()\n var days = Math.floor(date3 \/ (24 * 3600 * 1000))\n var leave1 = date3 % (24 * 3600 * 1000) \n var hours = Math.floor(leave1 \/ (3600 * 1000))\n var leave2 = leave1 % (3600 * 1000)\n var minutes = Math.floor(leave2 \/ (60 * 1000))\n var leave3 = leave2 % (60 * 1000)\n if (days < 1 && hours < 1) { return minutes + \"分前\" } else if (days < 1) { return hours + \"小时 \" + minutes + \"分前\" } else {\n if (days < 7) {\n return days + \"天 \" + hours + \"小时前 \"\n } else { return time }\n }\n}\n\nfunction formatCount(count) {\n if (count < 10000) return count.toString();\n const inWan = (count \/ 10000).toFixed(2);\n return inWan.endsWith('.00') \n ? `${inWan.split('.')[0]}万` \n : `${inWan}万`;\n}\n\nresult = '📅 '+formatDate(time)+\" 📝\"+formatCount(java.getString(\"$.mblog.comments_count\"))+\" ❤️\"+formatCount(java.getString(\"$.mblog.attitudes_count\"))+\" @\"+java.getString(\"$.mblog.user.screen_name\");\n}else{\n\tresult = java.getString(\"$.desc2\")\n\t\t}<\/js>", "ruleTitle": "$.pic_id||$.title||$.mblog.text||$.title_sub||$..name\n<js>##<.*?><\/js>\n<js>##\\n##|<\/js>\n<js>##.*话题\\|超话\\|地点.*<\/js>\n<js>##.*综合\\|用户\\|实时.*<\/js>", "singleUrl": false, "sortUrl": "番茄免费小说::data:page=1;base64,{{java.base64Encode(\"https:\/\/m.weibo.cn\/api\/container\/getIndex?containerid=100808cc3c11fcbbf8f2b8ea33e450a8343465_-_feed&page=1\")}},{\"type\":\"\"}\n\n\n\n搜索超话::https:\/\/m.weibo.cn\/api\/container\/getIndex?containerid=100103type%3D98%26q%3D{{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=\"200\" y=\"100\" font-family=\"Arial, sans-serif\" font-size=\"70\" fill=\"#333\" font-weight=\"bold\">输入要搜索的超话名称<\/text><\/svg>`));if(page==1){let a=\"\";try{a=java.getVerificationCode('data:image\/svg+xml;base64,'+svg);}catch(e){java.log(e)};if(a==\"\"){a=Map(\"searchname\")??\"\"}setHeaders(\"searchname=\"+a);a}else{Map(\"searchname\")};}}%23&isnewpage=1&luicode=10000011&lfid=100103type%3D1%26q%3D{{Map(\"searchname\")}}%26t%3D&page_type=searchall&page={{page}}", "sourceComment": "1、在【搜索超话】点击右上角三点刷新分类或下拉刷新,会弹出输入框,将复制的内容换行粘贴进分类URL\n2、设置源变量可以搜索超话内容【只有处在【首页】才能搜索】,如要切换其他专区需要删除源变量", "sourceGroup": "阅读", "sourceIcon": "https:\/\/is1-ssl.mzstatic.com\/image\/thumb\/Purple221\/v4\/52\/6a\/04\/526a04f7-ccfd-612e-64cb-ece08b01b4e6\/WeiboAppIcon-0-0-1x_U007epad-0-1-0-0-85-220.png\/492x0w.webp", "sourceName": " 📖\n微博超话", "sourceUrl": "https:\/\/m.weibo.cn#微博超话" }