// ==UserScript==
// @name 98堂-预览
// @version 1.9.4
// @namespace https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94
// @author 星宿老魔
// @description 98堂[原色花堂]帖子预览图片及链接,支持无缝翻页
// @match https://sehuatang.org/*
// @match https://sehuatang.net/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=sehuatang.org
// @license MIT
// @grant none
// @run-at document-start
// ==/UserScript==
(function(){"use strict";const CONFIG={defaults:{maxPreviewImages:4,concurrencyLimit:20,cacheEnabled:!0,cacheSize:50,cacheTTL:6e5,lazyLoadThreshold:2,
networkTimeout:5e3},get(e){return JSON.parse(localStorage.getItem("SHT_PREVIEW_CONFIG")||"{}")[e]??this.defaults[e]},set(e,t){
const n=JSON.parse(localStorage.getItem("SHT_PREVIEW_CONFIG")||"{}");n[e]=t,localStorage.setItem("SHT_PREVIEW_CONFIG",JSON.stringify(n))},getAll(){
const e=JSON.parse(localStorage.getItem("SHT_PREVIEW_CONFIG")||"{}");return{...this.defaults,...e}}},e=class{static inject(){if(this.injected)return
;const e=document.createElement("style")
;e.textContent='.sht-panel{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:360px;background:#f4f4f4;border-radius:6px;box-shadow:0 5px 20px rgba(0,0,0,0.2);z-index:10001;font-family:sans-serif;display:none;flex-direction:column}.sht-header{padding:16px 20px;font-size:16px;font-weight:600;color:#333;background:#e9e9e9;border-bottom:1px solid #ddd;border-radius:6px 6px 0 0;cursor:move;user-select:none}.sht-content{padding:20px}.sht-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:15px}.sht-label{font-size:14px;color:#555}.sht-select{padding:8px 12px;border-radius:5px;border:1px solid #ccc;font-size:14px;cursor:pointer;background:white;min-width:120px}.sht-footer{display:flex;justify-content:flex-end;padding:15px 20px;background:#e9e9e9;border-top:1px solid #ddd;border-radius:0 0 6px 6px}.sht-btn{padding:8px 16px;border:none;border-radius:5px;font-size:14px;cursor:pointer}.sht-btn-primary{background:#4d84c6;color:white}.sht-btn-secondary{background:#ccc;color:#333;margin-left:10px}.sht-close{position:absolute;top:16px;right:16px;width:32px;height:32px;border:none;border-radius:50%;background:rgba(0,0,0,0.1);color:#333;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.sht-card{position:relative;padding:15px;border:1px solid #e0e0e0;border-radius:6px;margin:20px;background:#fff;width:calc(100% - 40px);box-sizing:border-box}.sht-img-grid{display:flex;flex-wrap:nowrap;align-items:flex-start;gap:8px;width:100%}.sht-img-item{overflow:hidden;border-radius:4px;position:relative;cursor:pointer;height:300px}.sht-img-item-single{overflow:hidden;border-radius:4px;position:relative;cursor:pointer;height:300px}.sht-img{width:100%;height:100%;object-fit:cover}.sht-img-item-single .sht-img{object-position:top}.sht-links{margin:6px 0;padding:4px;background:#f8f9fa;border:1px solid #e0e0e0;border-radius:4px;width:100%;box-sizing:border-box}.sht-link-title{font-weight:bold;margin-bottom:6px;font-size:13px}.sht-link-item{background:white;border:1px solid #ddd;padding:2px 4px;border-radius:3px;margin-bottom:2px;word-break:break-all;cursor:pointer;font-size:11px}.sht-nav-toggle{position:relative;display:inline-block;width:38px;height:20px}.sht-nav-toggle input{opacity:0;width:0;height:0}.sht-nav-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ddd;border-radius:10px}.sht-nav-slider:before{position:absolute;content:"";height:16px;width:16px;left:2px;bottom:2px;background:white;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,0.2)}.sht-nav-toggle input:checked+.sht-nav-slider{background:#4d84c6}.sht-nav-toggle input:checked+.sht-nav-slider:before{transform:translateX(18px)}.sht-restore{position:fixed;right:0;bottom:10px;z-index:9997;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 5px;border-radius:5px 0 0 5px;box-shadow:-1px 1px 5px rgba(0,0,0,0.2);background:rgba(50,50,50,0.7);border:none;box-sizing:border-box;cursor:pointer;color:white;font-size:11px;letter-spacing:2px;writing-mode:vertical-rl;text-orientation:mixed}',
document.head.appendChild(e),this.injected=!0}static createElement(e,t,n){const i=document.createElement(e);return t&&(i.className=t),
n&&(i.textContent=n),i}static setImageGridWidth(e,t){const n=`calc((100% - ${8*(t-1)}px) / ${t})`;Array.from(e.children).forEach(e=>{e.style.width=n,
e.style.flex="0 0 auto"})}};e.injected=!1;let t=e;class Lightbox{static create(e,t=[]){const n=document.createElement("div")
;n.style.cssText="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.9); display: flex; justify-content: center; align-items: center; z-index: 9999; cursor: pointer;"
;const i=document.createElement("img");if(i.src=e,i.style.cssText="max-width: 90%; max-height: 90%; object-fit: contain; border: 2px solid white;",
n.appendChild(i),t.length>1){let o=t.indexOf(e);const r=()=>{a.style.display=o>0?"flex":"none",s.style.display=o<t.length-1?"flex":"none",
c.textContent=`${o+1} / ${t.length}`},a=document.createElement("div");a.innerHTML="‹",
a.style.cssText="position: absolute; left: 20px; top: 50%; transform: translateY(-50%); width: 50px; height: 50px; background-color: rgba(255, 255, 255, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 30px; color: white; cursor: pointer; z-index: 10000;",
a.addEventListener("click",e=>{e.stopPropagation(),o>0&&(o--,i.src=t[o],r())}),n.appendChild(a);const s=document.createElement("div");s.innerHTML="›",
s.style.cssText="position: absolute; right: 20px; top: 50%; transform: translateY(-50%); width: 50px; height: 50px; background-color: rgba(255, 255, 255, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 30px; color: white; cursor: pointer; z-index: 10000;",
s.addEventListener("click",e=>{e.stopPropagation(),o<t.length-1&&(o++,i.src=t[o],r())}),n.appendChild(s);const c=document.createElement("div")
;c.style.cssText="position: absolute; top: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 8px 16px; border-radius: 20px; font-size: 14px; z-index: 10000;",
n.appendChild(c),r()}n.addEventListener("click",e=>{e.target===i||e.target?.closest('div[style*="position: absolute"]')||document.body.removeChild(n)
}),document.body.appendChild(n)}}class PreviewSelector{static create(){const e=CONFIG.get("maxPreviewImages"),t=document.createElement("a")
;t.href="javascript:;",t.textContent=`预览${e}张图`,t.title="悬停选择预览图数量",t.setAttribute("hidefocus","true");let n=null;return t.onmouseenter=()=>{void 0,
n&&n.parentNode&&n.parentNode.removeChild(n),n=this.createTempMenu(e),document.body.appendChild(n);const i=t.getBoundingClientRect()
;n.style.left=i.left+"px",n.style.top=i.bottom+2+"px"},t.onmouseleave=()=>{void 0,setTimeout(()=>{
n&&n.parentNode&&!n.matches(":hover")&&(n.parentNode.removeChild(n),n=null)},200)},t}static createTempMenu(e){const t=document.createElement("div")
;return t.style.cssText="\n position: fixed;\n background: white;\n border: 2px solid #ccc;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n z-index: 99999;\n padding: 4px 0;\n min-width: 90px;\n ",
[3,4,5].forEach(n=>{const i=document.createElement("div");i.textContent=`${n}张图`,
i.style.cssText=`\n padding: 8px 15px;\n cursor: pointer;\n font-size: 13px;\n color: ${n===e?"#2c5aa0":"#333"};\n background: ${n===e?"#f0f8ff":"white"};\n font-weight: ${n===e?"bold":"normal"};\n `,
i.onmouseenter=()=>{n!==e&&(i.style.background="#e6f7ff")},i.onmouseleave=()=>{i.style.background=n===e?"#f0f8ff":"white"},i.onclick=e=>{
e.preventDefault(),e.stopPropagation(),CONFIG.set("maxPreviewImages",n),window.location.reload()},t.appendChild(i)}),t.onmouseenter=()=>{void 0},
t.onmouseleave=()=>{void 0,setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},100)},t}}class UIComponents{
static createToggleSwitch(e,options){const n=document.createElement("div");n.style.display="flex",n.style.alignItems="center"
;const i=document.createElement("span");i.textContent=`${e}:`,i.style.cssText="font-size: 13px; color: #666; margin-right: 6px; line-height: 20px;",
n.appendChild(i);const o=t.createElement("label","sht-nav-toggle"),r=document.createElement("input");r.type="checkbox"
;const a=t.createElement("span","sht-nav-slider");o.appendChild(r),o.appendChild(a),n.appendChild(o)
;let s=null===localStorage.getItem(options.storageKeyEnabled)?options.defaultEnabled||!1:"true"===localStorage.getItem(options.storageKeyEnabled)
;return r.addEventListener("change",()=>{s=r.checked,localStorage.setItem(options.storageKeyEnabled,String(s)),
s?options.onEnable():options.onDisable()}),r.checked=s,s&&options.onEnable(),n}static setupSearchTitleContainer(){
const e=document.querySelector(".sttl.mbn");return e?(e.style.display="flex",e.style.justifyContent="space-between",e.style.alignItems="center",
e):null}static createLinksElement(e){const n=[...e.ed2k,...e.magnet,...e.xunlei,...e.baidu];if(0===n.length)return null
;const i=t.createElement("div","sht-links");if(n.forEach((e,n)=>{const o=document.createElement("div");o.style.marginBottom="4px"
;const r=t.createElement("div","sht-link-item",e);r.title="点击复制链接",r.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation(),
navigator.clipboard.writeText(e).catch(()=>{})}),o.appendChild(r),n>0&&(o.style.display="none",o.classList.add("hidden-link")),i.appendChild(o)}),
n.length>1){const e=document.createElement("button");e.textContent=`显示剩余 ${n.length-1} 个链接`,
e.style.cssText="margin-top: 5px; cursor: pointer; border: 1px solid #ccc; background-color: #f0f0f0; padding: 5px 10px; border-radius: 4px;";let t=!1
;e.addEventListener("click",o=>{o.preventDefault(),o.stopPropagation(),t=!t,i.querySelectorAll(".hidden-link").forEach(e=>{
e.style.display=t?"block":"none"}),e.textContent=t?"收起链接":`显示剩余 ${n.length-1} 个链接`}),i.appendChild(e)}return i}static createNormalPageToggle(options){
const e=document.querySelector("#nv ul");if(!e)return;const t=document.createElement("li"),n=document.createElement("div")
;n.id="nav-toggle-infinite-scroll";const i=document.createElement("a");i.href="javascript:;",i.textContent="无缝翻页",n.appendChild(i),t.appendChild(n),
e.appendChild(t);const o=document.createElement("li"),r=document.createElement("div");r.id="nav-preview-selector";const a=PreviewSelector.create()
;r.appendChild(a),o.appendChild(r),e.appendChild(o)
;let s=null===localStorage.getItem(options.storageKeyEnabled)?options.defaultEnabled||!1:"true"===localStorage.getItem(options.storageKeyEnabled)
;const c=i.offsetWidth||68,l=()=>{
s?(n.classList.add("a"),i.style.cssText=`\n background-color: #840000 !important;\n background-image: url(/static/image/common/nv_a.png) !important;\n background-repeat: no-repeat !important;\n background-position: 50% -33px !important;\n color: #fff !important;\n font-weight: 700 !important;\n height: 33px !important;\n line-height: 33px !important;\n padding: 0 8px !important;\n min-width: ${c}px !important;\n width: ${c}px !important;\n box-sizing: border-box !important;\n text-align: center !important;\n display: inline-block !important;\n `):(n.classList.remove("a"),
n.classList.remove("hover"),i.style.cssText="")};n.addEventListener("click",e=>{e.preventDefault(),s=!s,
localStorage.setItem(options.storageKeyEnabled,String(s)),l(),s?options.onEnable():options.onDisable()}),l(),s&&options.onEnable()}
static createSearchPageSingleToggle(e){const t=this.setupSearchTitleContainer();if(!t)return;const n=document.createElement("div")
;n.style.display="flex",n.style.alignItems="center";const i=this.createToggleSwitch("无缝翻页",e);n.appendChild(i),t.appendChild(n)}
static createSearchPageDualToggles(e,t){const n=this.setupSearchTitleContainer();if(!n)return;const i=document.createElement("div")
;i.style.display="flex",i.style.alignItems="center",i.style.gap="20px",i.appendChild(this.createToggleSwitch("无缝翻页",e)),
i.appendChild(this.createToggleSwitch("移除隐藏贴",t)),n.appendChild(i)}static createFixedRestoreButton(config){
window.activeRestoreButton&&window.activeRestoreButton.remove();const e=t.createElement("div","sht-restore");return e.id=config.id,
e.innerHTML=config.labelHtml,e.addEventListener("click",config.onClick),document.body.appendChild(e),window.activeRestoreButton=e,e}
static createUnifiedInfoCard(e,n,i,o){e.innerHTML="",e.className="sht-card";const r=document.createElement("a");let a=n.textContent||"预览"
;if(a=a.replace(/\s+/g," ").trim(),r.textContent=a,r.href=n.href,r.target="_blank",
r.style.cssText="font-size: 16px; font-weight: bold; color: #2c5aa0; margin-bottom: 15px; line-height: 1.4; cursor: pointer; text-decoration: underline; display: block;",
r.addEventListener("click",e=>{e.ctrlKey||e.metaKey||e.shiftKey||(e.preventDefault(),window.open(n.href,"_blank"))}),e.appendChild(r),i.length>0){
const n=t.createElement("div","sht-img-grid");i.forEach(e=>{
const o=e.getAttribute("file"),r=1===i.length?"sht-img-item-single":"sht-img-item",a=t.createElement("div",r),s=t.createElement("img","sht-img")
;s.src=o,a.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),Lightbox.create(o,i.map(e=>e.getAttribute("file")))}),a.appendChild(s),
n.appendChild(a)}),t.setImageGridWidth(n,i.length),e.appendChild(n)}const s=this.createLinksElement(o);s&&(s.className="sht-links",e.appendChild(s))}}
const n=class{static info(e){void 0}static error(e,t){void 0}};n.PREFIX="[98堂]";let i=n;class ConcurrencyManager{constructor(e){this.queue=[],
this.activeCount=0,this.limit=e}async addTask(e){return new Promise((t,n)=>{this.queue.push({task:e,resolve:t,reject:n}),this._next()})}_next(){
if(this.activeCount>=this.limit||0===this.queue.length)return;this.activeCount++;const{task:e,resolve:t,reject:n}=this.queue.shift()
;e().then(t,n).finally(()=>{this.activeCount--,this._next()})}}class PreviewCache{constructor(){this.cache=new Map,this.maxSize=50,this.normalTtl=6e5,
this.highTtl=18e5}set(e,t,n="normal"){if(this.cleanup(),this.cache.size>=this.maxSize)for(const[i,o]of this.cache.entries())if("normal"===o.priority){
this.cache.delete(i);break}this.cache.set(e,{data:t,timestamp:Date.now(),priority:n})}get(e){const t=this.cache.get(e);if(!t)return null
;const n="high"===t.priority?this.highTtl:this.normalTtl;return Date.now()-t.timestamp>n?(this.cache.delete(e),null):t.data}has(e){
const t=this.cache.get(e);if(!t)return!1;const n="high"===t.priority?this.highTtl:this.normalTtl
;return!(Date.now()-t.timestamp>n&&(this.cache.delete(e),1))}cleanup(){const e=Date.now();for(const[t,n]of this.cache.entries()){
const i="high"===n.priority?this.highTtl:this.normalTtl;e-n.timestamp>i&&this.cache.delete(t)}}clear(){this.cache.clear()}size(){
return this.cleanup(),this.cache.size}}const o=new PreviewCache;async function r(e,options={}){
const{timeout:t=5e3,...n}=options,i=new AbortController,o=setTimeout(()=>i.abort(),t);try{const t=await fetch(e,{...n,signal:i.signal})
;return clearTimeout(o),t}catch(r){throw clearTimeout(o),r}}async function a(e,t="normal"){const n=o.get(e);if(n)return n;try{
const n=await r(e),i=await n.text(),a=p((new DOMParser).parseFromString(i,"text/html"));return o.set(e,a,t),a}catch(a){return i.error("获取失败:",a),null}
}function debounce(e,t){let n;return(...i)=>{clearTimeout(n),n=window.setTimeout(()=>e(...i),t)}}function throttle(e,t){let n=0;return(...i)=>{
const o=Date.now();o-n>=t&&(e(...i),n=o)}}class LinkExtractor{static extractAllLinks(e){const t={ed2k:[],magnet:[],xunlei:[],baidu:[]};try{
this.extractResourceLinks(e,t),this.extractHtmlNetworkDiskLinks(e,t),this.extractCodeBlockLinks(e,t),
0===t.magnet.length&&this.extractMagnetFromFullPage(e,t),this.deduplicateLinks(t)}catch(n){i.error("链接提取错误",n)}return t}
static extractResourceLinks(e,t){e.querySelectorAll('a[href^="magnet:"], a[href^="ed2k:"]').forEach(e=>{const n=e.href;n&&this.categorizeLink(n,t)}),
e.querySelectorAll('a[href*="ed2k://"], a[href*="magnet:"]').forEach(e=>{const n=e.href;n&&this.categorizeLink(n,t)})
;const n=(e.body.textContent||"").match(/ed2k:\/\/\|file\|[^|]+\|\d+\|[A-F0-9]+\|\//gi);n&&n.forEach(e=>t.ed2k.push(e.trim()))}
static extractHtmlNetworkDiskLinks(e,t){e.querySelectorAll('a[href*="pan.xunlei.com/s/"], a[href*="pan.baidu.com/s/"]').forEach(e=>{
const n=e.getAttribute("href")
;n&&(n.includes("pan.xunlei.com/s/")?t.xunlei.push(this.combineNetworkDiskLink(e,n)):n.includes("pan.baidu.com/s/")&&t.baidu.push(this.combineNetworkDiskLink(e,n)))
})}static extractCodeBlockLinks(e,t){e.querySelectorAll(".blockcode").forEach(e=>{
const n=e.textContent||"",i=n.match(/magnet:\?xt=urn:btih:[a-fA-F0-9]{40}/g);if(i)i.forEach(e=>t.magnet.push(e.trim()));else{
const e=n.match(/\b([a-fA-F0-9]{40})\b/g);e&&e.length<=3&&e.forEach(e=>t.magnet.push(`magnet:?xt=urn:btih:${e}`))}
const o=n.match(/https:\/\/pan\.xunlei\.com\/s\/[a-zA-Z0-9_-]+/g);o&&o.forEach(e=>t.xunlei.push(e.trim()))
;const r=n.match(/https:\/\/pan\.baidu\.com\/s\/[a-zA-Z0-9_-]+/g);r&&r.forEach(e=>t.baidu.push(e.trim()))})}static extractMagnetFromFullPage(e,t){
const n=e.querySelector(".t_f, #postmessage, .pcb"),i=n?n.textContent||"":e.body.textContent||"",o=i.match(/magnet:\?xt=urn:btih:[a-fA-F0-9]{40}/g)
;if(o)o.forEach(e=>t.magnet.push(e.trim()));else{const e=i.match(/\b([a-fA-F0-9]{40})\b/g)
;e&&e.slice(0,3).forEach(e=>t.magnet.push(`magnet:?xt=urn:btih:${e}`))}}static categorizeLink(e,t){
e.startsWith("ed2k://")?t.ed2k.push(e):e.startsWith("magnet:")?t.magnet.push(e):e.includes("pan.xunlei.com")?t.xunlei.push(e):e.includes("pan.baidu.com")&&t.baidu.push(e)
}static deduplicateLinks(e){e.ed2k=[...new Set(e.ed2k)],e.magnet=[...new Set(e.magnet)],e.xunlei=[...new Set(e.xunlei)],e.baidu=[...new Set(e.baidu)]}
static hasAnyContent(e){return e.ed2k.length>0||e.magnet.length>0||e.xunlei.length>0||e.baidu.length>0}static combineNetworkDiskLink(e,t){
if(t.includes("?pwd="))return t;const n=(e.parentElement?.textContent||"").match(/提取码[::]\s*([a-zA-Z0-9]+)/);return n?`${t}?pwd=${n[1]}`:t}}
function s(e){return LinkExtractor.extractAllLinks(e)}const c=class{static createPageNumElement(){
document.getElementById("page-number-display")||(this.pageNumDisplay=document.createElement("div"),this.pageNumDisplay.id="page-number-display",
this.pageNumDisplay.style.cssText="position: fixed; z-index: 9998; user-select: none; display: none; background-color: rgba(50,50,50,0.5); color: white; padding: 5px; border-radius: 5px; font-size: 12px; text-align: center;",
document.body.appendChild(this.pageNumDisplay))}static updateAndSaveForumState(){this.updateFloatingPageNumber(),this.saveForumState()}
static updateAndSaveSearchState(){const e=document.querySelector(".sttl .emfont")?.textContent;if(e){let t="1"
;const n=document.querySelector(".pg strong");if(n)t=n.textContent||"1";else if(!document.querySelector(".pg a.nxt")){
const e=window.location.href.match(/[?&]page=(\d+)/);e&&(t=e[1])}const i=new URLSearchParams(window.location.search);i.delete("page")
;const o=window.location.pathname+"?"+i.toString();localStorage.setItem("lastSearchState",JSON.stringify({keyword:e,page:t,baseUrl:o}))}}
static updateFloatingPageNumber(){if(!this.pageNumDisplay)return;const e=document.getElementById("scrolltop")
;if(e&&e.offsetHeight>0&&"hidden"!==window.getComputedStyle(e).visibility){const t=e.getBoundingClientRect()
;this.pageNumDisplay.style.display="block",this.pageNumDisplay.style.top=t.top-this.pageNumDisplay.offsetHeight-5+"px",
this.pageNumDisplay.style.left=`${t.left}px`,this.pageNumDisplay.style.width=`${t.width}px`,this.pageNumDisplay.style.boxSizing="border-box"
;const n=document.querySelector(".pg strong")?.textContent||"1";this.pageNumDisplay.textContent=`第${n}页`}else this.pageNumDisplay.style.display="none"
}static saveForumState(){const e=document.querySelector("#pt .z a:last-of-type")?.textContent,t=document.querySelector(".pg strong")?.textContent||"1"
;if(e){const n=document.querySelector('.pg a[href*="page="]')||document.querySelector('.pg a[href*="-"]');let i=null
;n&&(i=n.href.replace(/([?&]page=)\d+/,"$1__PAGE__").replace(/-\d+\.html/,"-__PAGE__.html")),localStorage.setItem("lastForumState",JSON.stringify({
sectionName:e,page:t,urlTemplate:i}))}}static setupForumRestore(){
const e=JSON.parse(localStorage.getItem("lastForumState")||"null"),t=document.querySelector("#pt .z a:last-of-type")?.textContent,n=parseInt(new URLSearchParams(window.location.search).get("page")||window.location.pathname.match(/-(\d+)\.html$/)?.[1]||"1",10)
;if(e&&e.sectionName&&e.urlTemplate){const i=e.sectionName===t,o=parseInt(e.page,10)>n;if(!i||i&&o){
const t=`<span style="writing-mode: vertical-rl; text-orientation: mixed; font-size: 11px; color: white; letter-spacing: 2px;">恢复: ${e.sectionName} (${e.page})</span>`
;window.activeRestoreButton=this.createFixedRestoreButton({id:"restore-forum-btn",labelHtml:t,onClick:()=>{
const t=e.urlTemplate.replace("__PAGE__",e.page);window.location.href=t}})}}}static setupSearchRestore(){
const e=JSON.parse(localStorage.getItem("lastSearchState")||"null"),t=document.querySelector(".sttl .emfont")?.textContent,n=parseInt(new URLSearchParams(window.location.search).get("page")||"1",10)
;if(e&&e.keyword){const i=e.keyword===t,o=parseInt(e.page,10)>n;if(!i||i&&o){
const t=`<span style="writing-mode: vertical-rl; text-orientation: mixed; font-size: 11px; color: white; letter-spacing: 2px;">恢复: ${e.keyword} (${e.page})</span>`
;window.activeRestoreButton=this.createFixedRestoreButton({id:"restore-search-btn",labelHtml:t,onClick:()=>{
window.location.href=`${e.baseUrl}&page=${e.page}`}})}}}static setupStateTracking(){const e=throttle(()=>this.updateAndSaveForumState(),100)
;window.addEventListener("scroll",e,{passive:!0}),window.addEventListener("resize",e,{passive:!0});const t=document.getElementById("scrolltop")
;t&&new MutationObserver(e).observe(t,{attributes:!0,attributeFilter:["style","class"]})}static createFixedRestoreButton(config){
window.activeRestoreButton&&window.activeRestoreButton.remove();const e=document.createElement("div");return e.className="sht-restore",e.id=config.id,
e.innerHTML=config.labelHtml,e.addEventListener("click",config.onClick),document.body.appendChild(e),e}};c.pageNumDisplay=null;let l=c;const d=class{
static setContentProcessor(e){this.contentProcessor=e}static enableNormalScroll(e,t){if(this.scrollHandler)return
;const n=document.querySelector(".pg a.nxt");n&&(this.nextUrl=n.href,this.createNormalLoadingIndicator(),this.setupNormalScrollListener(e,t),
l.updateAndSaveForumState())}static enableSearchScroll(){if(this.scrollHandler)return;this.initializePagination()
;const e=document.getElementById("sticky-scroll-container");e&&(this.scrollHandler=debounce(()=>{if(this.isLoading||!this.nextUrl)return
;const t=this.getVisiblePostsCount()<this.MIN_VISIBLE_POSTS?2*e.clientHeight:.8*e.clientHeight
;e.scrollTop+e.clientHeight>=e.scrollHeight-t&&this.loadSearchNext()},150),e.addEventListener("scroll",this.scrollHandler,{passive:!0}),
this.startContentMonitoring(),this.waitForImages(e).then(()=>{this.checkAndEnsureContent()}))}static disableScroll(){if(this.scrollHandler){
const e=document.getElementById("sticky-scroll-container")
;e?e.removeEventListener("scroll",this.scrollHandler):window.removeEventListener("scroll",this.scrollHandler),this.scrollHandler=null}
this.stopContentMonitoring(),this.loadingIndicator&&(this.loadingIndicator.style.display="none"),l.updateAndSaveForumState(),
this.redirectToCurrentPage()}static createNormalLoadingIndicator(){this.loadingIndicator||(this.loadingIndicator=document.createElement("div"),
this.loadingIndicator.textContent="正在加载更多内容...",this.loadingIndicator.style.cssText="text-align: center; padding: 20px; display: none;",
document.querySelector("#threadlist")?.insertAdjacentElement("afterend",this.loadingIndicator))}static initializePagination(){
const e=document.querySelector(".pg");e?.querySelector("a.nxt")&&(this.nextUrl=e.querySelector("a.nxt").href);const t=document.createElement("div")
;t.id="search-loading-indicator",t.style.cssText="text-align: center; padding: 20px; display: none;",
document.getElementById("sticky-scroll-container")?.appendChild(t),this.loadingIndicator=t}static setupNormalScrollListener(e,t){
this.scrollHandler=async()=>{
!this.isLoading&&this.nextUrl&&document.documentElement.scrollTop+document.documentElement.clientHeight>=document.documentElement.scrollHeight-500&&await this.loadNormalNext(e,t)
},window.addEventListener("scroll",this.scrollHandler,{passive:!0})}static async loadNormalNext(e,t){this.isLoading=!0,
this.loadingIndicator&&(this.loadingIndicator.style.display="block");try{
const n=await fetch(this.nextUrl),i=await n.text(),o=(new DOMParser).parseFromString(i,"text/html"),r=document.querySelector("table#threadlisttableid"),a=o.querySelectorAll("table#threadlisttableid > tbody[id^=normalthread_]")
;a.length>0&&r&&(await this.appendNormalContent(r,a,e,t),this.updatePagination(o)),this.updateNextPageUrl()}catch(n){i.error("翻页失败:",n),
this.loadingIndicator&&(this.loadingIndicator.textContent="加载失败")}finally{this.isLoading=!1,this.updateLoadingIndicator(),l.updateAndSaveForumState()}
}static async loadSearchNext(){if(this.isLoading||!this.nextUrl)return;this.isLoading=!0;const e=document.getElementById("search-loading-indicator")
;e&&(e.style.display="block",e.textContent="正在加载...");try{
const e=await this.fetchWithTimeout(this.nextUrl),t=await e.text(),n=(new DOMParser).parseFromString(t,"text/html"),i=document.querySelector("#threadlist > ul"),o=n.querySelector("#threadlist > ul")
;o&&o.children.length>0&&i&&(this.contentProcessor&&this.contentProcessor.processSearchContainer&&await this.contentProcessor.processSearchContainer(o,!1),
Array.from(o.children).forEach(e=>{i.appendChild(e)}));const r=n.querySelector(".pg"),a=document.querySelector(".pg")
;a&&r?a.replaceWith(r):!a&&r&&document.querySelector(".tl")?.appendChild(r);const s=document.querySelector(".pg a.nxt");this.nextUrl=s?s.href:""
}catch(t){i.error("翻页失败:",t),e&&(e.textContent="加载失败"),this.nextUrl=""}finally{this.isLoading=!1,
e&&(this.nextUrl?e.style.display="none":e.textContent="已加载全部内容")}}static async appendNormalContent(e,t,n,i){const o=document.createDocumentFragment()
;t.forEach(e=>o.appendChild(e)),e.appendChild(o),n&&await n.processNewThreads(e),i&&i.applyStickPostHidingToNewContent()}static updatePagination(e){
const t=e.querySelector(".pg"),n=document.querySelector(".pg");n&&t&&n.replaceWith(t)}static updateNextPageUrl(){
const e=document.querySelector(".pg a.nxt");this.nextUrl=e?e.href:""}static updateLoadingIndicator(){
this.loadingIndicator&&(this.nextUrl?this.loadingIndicator.style.display="none":this.loadingIndicator.textContent="已加载全部内容")}
static redirectToCurrentPage(){const e=parseInt(document.querySelector(".pg strong")?.textContent||"1",10);if(isNaN(e))window.location.reload();else{
const t=new URL(window.location.href);t.searchParams.set("page",e.toString()),window.location.href=t.toString()}}
static async fetchWithTimeout(e,options={}){const t=new AbortController,n=setTimeout(()=>t.abort(),8e3);try{const i=await fetch(e,{...options,
signal:t.signal});return clearTimeout(n),i}catch(i){throw clearTimeout(n),i}}static getVisiblePostsCount(){
const e=document.querySelectorAll("#threadlist .pbw");let t=0;return e.forEach(e=>{const n=window.getComputedStyle(e)
;"none"!==n.display&&"hidden"!==n.visibility&&"0"!==n.opacity&&t++}),t}static startContentMonitoring(){if(this.contentObserver)return
;const e=document.getElementById("sticky-scroll-container");e&&(this.contentObserver=new MutationObserver(()=>{setTimeout(()=>{
this.checkAndEnsureContent()},100)}),this.contentObserver.observe(e,{childList:!0,subtree:!0}))}static stopContentMonitoring(){
this.contentObserver&&(this.contentObserver.disconnect(),this.contentObserver=null)}static async checkAndEnsureContent(){
if(this.isLoading||!this.nextUrl)return;const e=document.getElementById("sticky-scroll-container");if(!e)return
;const t=this.getVisiblePostsCount(),n=e.scrollHeight/e.clientHeight
;(t<this.MIN_VISIBLE_POSTS||n<this.MIN_CONTENT_HEIGHT_RATIO)&&(await this.loadSearchNext(),setTimeout(()=>{this.checkAndEnsureContent()},500))}
static waitForImages(e){const t=Array.from(e.querySelectorAll("img"));if(0===t.length)return Promise.resolve();const n=t.map(e=>new Promise(t=>{
e.complete?t():(e.addEventListener("load",()=>t(),{once:!0}),e.addEventListener("error",()=>t(),{once:!0}))}));return Promise.all(n).then(()=>{})}
static async ensureSufficientContent(){let e=0;const t=10;for(;this.nextUrl&&e<t;){const t=document.getElementById("sticky-scroll-container")
;if(!t)break;const n=t.scrollHeight,i=t.clientHeight,o=document.querySelectorAll("#threadlist .pbw").length;if(n>1.5*i||o>=5)break
;await this.loadSearchNext(),e++,await new Promise(e=>setTimeout(e,300))}}};d.scrollHandler=null,d.isLoading=!1,d.nextUrl="",d.loadingIndicator=null,
d.contentProcessor=null,d.contentObserver=null,d.MIN_VISIBLE_POSTS=8,d.MIN_CONTENT_HEIGHT_RATIO=1.8;let h=d;function p(e){return{
images:Array.from(e.querySelectorAll("img.zoom")).filter(e=>{const t=e.getAttribute("file")
;return!(!t||t.includes("static"))&&(430!==parseInt(e.getAttribute("width")||"0")&&!(t.toLowerCase().endsWith(".png")&&(t.includes("7pzzv.us")||t.includes("iili.io"))))
}),links:s(e)}}const u=Object.freeze(Object.defineProperty({__proto__:null,ConcurrencyManager:ConcurrencyManager,LinkExtractor:LinkExtractor,Logger:i,
PreviewCache:PreviewCache,ScrollManager:h,StateManager:l,debounce:debounce,extractDownloadLinks:s,extractPostPreviewData:p,fetchWithCache:a,
fetchWithTimeout:r,previewCache:o,throttle:throttle},Symbol.toStringTag,{value:"Module"}));class SettingsApplier{static applyInitialStickPostHiding(){
setTimeout(()=>{this.applyStickPostHiding()},100)}static applyStickPostHidingToNewContent(){
this.hideStickPostsAndAdminPosts(":not(.hide-processed)",!0)}static applyDefaultTimeSort(){
const e=window.location.href,t=new URLSearchParams(window.location.search),n=t.get("mod"),i=t.get("fid")
;("forumdisplay"===n&&i||/forum-\d+-\d+\.html/.test(e))&&"dateline"!==t.get("orderby")&&this.redirectToTimeSortedPage(e,n,i)}
static applyStickPostHiding(){this.hideStickPostsAndAdminPosts("",!1)}static hideStickPostsAndAdminPosts(e,t){
document.querySelectorAll(`#threadlisttableid tbody[id^="stickthread_"]${e}`).forEach(e=>{e.style.display="none",t&&e.classList.add("hide-processed")
}),document.querySelectorAll(`#threadlisttableid tbody[id^="normalthread_"]${e}`).forEach(e=>{const n=e.querySelector("em a")
;n&&n.textContent?.includes("版务管理")&&(e.style.display="none"),t&&e.classList.add("hide-processed")})}static redirectToTimeSortedPage(e,t,n){let i
;if("forumdisplay"===t&&n){const t=new URL(e);t.searchParams.set("orderby","dateline"),t.searchParams.set("filter","author"),i=t.href}else{
const t=e.match(/forum-(\d+)-(\d+)\.html/);if(!t)return;i=`forum.php?mod=forumdisplay&fid=${t[1]}&page=${t[2]}&orderby=dateline&filter=author`}
window.location.href=i}}class ThreadRenderer{static async processSingleThread(e){const t=e.href,n=e.closest("tbody")
;if(n&&"imagePreviewTbody"!==n.nextElementSibling?.id&&!n.querySelector(".searchImagePreview")&&"true"!==n.dataset.previewProcessed){
n.dataset.previewProcessed="true";try{const i=await a(t);if(!i)return;const{images:o,links:r}=i,s=o.slice(0,CONFIG.get("maxPreviewImages"))
;if(0===s.length&&!LinkExtractor.hasAnyContent(r))return;this.renderSimpleThreadContent(e,n,s,r)}catch(o){i.error("处理失败:",o),
n&&(n.dataset.previewProcessed="false")}}}static renderSimpleThreadContent(e,n,i,o){t.inject();const r=e.closest("tr");r&&(r.style.display="none")
;const a=document.createElement("div");UIComponents.createUnifiedInfoCard(a,e,i,o);const s=document.createElement("tbody");s.id="imagePreviewTbody"
;const c=document.createElement("tr"),l=document.createElement("td");l.colSpan=5,l.style.cssText="padding: 0; border: 0;",l.appendChild(a),
c.appendChild(l),s.appendChild(c),n.after(s)}static async displayInitialThreads(){
const e=document.querySelectorAll("#threadlisttableid .s.xst"),t=new ConcurrencyManager(CONFIG.get("concurrencyLimit")),n=Array.from(e).map(e=>t.addTask(async()=>{
const t=e.closest("th, td");t?.querySelector("em a")?.textContent?.includes("版务管理")||await this.processSingleThread(e)}));await Promise.all(n)}
static async processNewThreads(e){const t=Array.from(e.querySelectorAll("tbody[id^=normalthread_]:not(.processed) a.s.xst"))
;await Promise.all(t.map(e=>{const t=e.closest("tbody");return t?.classList.add("processed"),
t?.querySelector("em a")?.textContent?.includes("版务管理")?Promise.resolve():this.processSingleThread(e)}))}}class NormalPageManager{static init(){
l.createPageNumElement(),l.setupForumRestore(),l.setupStateTracking(),this.setupToggle(),ThreadRenderer.displayInitialThreads(),
SettingsApplier.applyInitialStickPostHiding(),SettingsApplier.applyDefaultTimeSort()}static setupToggle(){UIComponents.createNormalPageToggle({
storageKeyEnabled:"normalPageInfiniteScroll",onEnable:()=>h.enableNormalScroll(ThreadRenderer,SettingsApplier),onDisable:()=>h.disableScroll(),
defaultEnabled:!1})}}class SearchLayoutManager{static applyStickyLayout(){const e=document.getElementById("ct");if(!e)return
;const t=document.getElementById("toptb"),n=e.querySelector("form.searchform"),i=e.querySelector(".tl");if(!i)return
;const o=i.querySelector(".sttl"),r=i.querySelector("#threadlist"),a=i.querySelector(".pgs"),s=document.getElementById("ft");if(!r)return
;s&&s.remove();const c=document.createElement("div");t&&c.appendChild(t),n&&c.appendChild(n),o&&c.appendChild(o);const l=document.createElement("div")
;l.id="sticky-scroll-container",l.appendChild(r);const d=document.createElement("div");a&&d.appendChild(a),e.innerHTML="",e.appendChild(c),
e.appendChild(l),e.appendChild(d),this.injectLayoutStyles()}static injectLayoutStyles(){const e=document.createElement("style")
;e.textContent="\n html, body { height: 100%; overflow: hidden; margin: 0; }\n #ct { height: 100% !important; display: flex; flex-direction: column; }\n #ct > div:nth-child(1) { flex-shrink: 0; overflow: hidden; }\n #sticky-scroll-container { flex-grow: 1; overflow-y: auto; border-top: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0; position: relative; }\n #ct > div:nth-child(3) { flex-shrink: 0; padding: 10px 0; background-color: #fff; border-top: 1px solid #e0e0e0; }\n .pgs.cl { margin-bottom: 0 !important; }\n .tl { width: 100% !important; max-width: none !important; padding: 0 20px !important; box-sizing: border-box !important; }\n #threadlist { width: 100% !important; max-width: none !important; }\n #threadlist > ul { width: 100% !important; max-width: none !important; padding: 0 !important; margin: 0 !important; }\n .pbw { width: 100% !important; max-width: none !important; box-sizing: border-box !important; margin: 25px 0 !important; }\n ",
document.head.appendChild(e)}static createRichPostCard(e,n,i,o){t.inject(),UIComponents.createUnifiedInfoCard(e,n,i,o)}}class SearchContentProcessor{
static async processSearchContainer(e,t=!1){return await this.displaySearchPreviews(e,t),e.querySelectorAll(".pbw").length}
static async displaySearchPreviews(e,t=!1){const n=e.querySelectorAll(".xs3 a"),o=Array.from(n).filter(e=>{const t=e.closest(".pbw")
;return e.href&&e.href.includes("thread")&&t&&!t.classList.contains("hidden-transparent")
}),r=new ConcurrencyManager(CONFIG.get("concurrencyLimit")),s=[],c=o.map(e=>r.addTask(async()=>{try{const n=e.href,i=e.closest(".pbw")
;if(!i||i.querySelector(".searchImagePreview")||i.querySelector('[id*="imagePreview"]')||"true"===i.dataset.previewProcessed)return
;i.dataset.previewProcessed="true";const r=t&&o.indexOf(e)<5,c=await a(n,r?"high":"normal");if(!c)return s.push({pbwContainer:i,link:e,hasContent:!1,
processed:!1,isHidden:this.isHiddenPost(i)}),void 0;const{images:l,links:d}=c,h=l.slice(0,CONFIG.get("maxPreviewImages"))
;if(!(h.length>0||LinkExtractor.hasAnyContent(d)))return s.push({pbwContainer:i,link:e,hasContent:!1,processed:!1,isHidden:this.isHiddenPost(i)}),
void 0;this.createRichPostCard(i,e,h,d),s.push({pbwContainer:i,link:e,hasContent:!0,processed:!0,isHidden:!1})}catch(n){i.error("处理失败:",n)
;const t=e.closest(".pbw");t&&(t.dataset.previewProcessed="false",s.push({pbwContainer:t,link:e,hasContent:!1,processed:!1,
isHidden:this.isHiddenPost(t)}))}}));await Promise.all(c),this.handleInvalidAndHiddenPosts(s)}static createRichPostCard(e,t,n,i){
SearchLayoutManager.createRichPostCard(e,t,n,i)}static handleInvalidAndHiddenPosts(e){e.filter(e=>!e.hasContent&&!e.processed).forEach(e=>{
e.isHidden&&e.pbwContainer.remove()})}static isHiddenPost(e){
const t=e.textContent||"",n=["该主题需要回复才能浏览","内容隐藏需要,请点击进去查看","隐藏内容","此帖被隐藏","权限不足","积分不足","回复可见","购买主题","付费内容","需要权限","您无权访问","内容隐藏需要"].some(e=>t.includes(e)),i=!!(e.querySelector(".locked")||e.querySelector(".permission-denied")||e.querySelector(".reply-to-view")),o=e.querySelector(".xs3 a")?.textContent||"",r=o.includes("隐藏")||o.includes("权限")||o.includes("回复可见")||o.includes("积分不足")
;return n||i||r}static reprocessExistingPosts(){document.querySelectorAll("#threadlist .pbw").forEach(e=>{this.isHiddenPost(e)&&e.remove()})}
static async showCachedContent(e){for(const t of e){const e=t.href,n=t.closest(".pbw");if(!n||"true"===n.dataset.previewProcessed)continue
;const{previewCache:i}=await Promise.resolve().then(()=>u);if(i.has(e)){const o=i.get(e);if(o){n.dataset.previewProcessed="true"
;const{images:e,links:i}=o,r=e.slice(0,CONFIG.get("maxPreviewImages"));(r.length>0||LinkExtractor.hasAnyContent(i))&&this.createRichPostCard(n,t,r,i)}
}}}static async loadRemainingContent(e){if(0===e.length)return
;const t=new ConcurrencyManager(CONFIG.get("concurrencyLimit")),n=e.map(e=>t.addTask(async()=>{const t=e.href,n=e.closest(".pbw")
;if(!n||"true"===n.dataset.previewProcessed)return;n.dataset.previewProcessed="true";const i=await a(t,"normal");if(i){
const{images:t,links:o}=i,r=t.slice(0,CONFIG.get("maxPreviewImages"));(r.length>0||LinkExtractor.hasAnyContent(o))&&this.createRichPostCard(n,e,r,o)}
}));await Promise.allSettled(n)}}class SearchPageManager{static init(){SearchLayoutManager.applyStickyLayout(),l.setupSearchRestore(),
this.setupToggle(),setTimeout(()=>{this.setupInitialContent()},0)}static async setupInitialContent(){
const e=document.querySelector("#threadlist > ul");e&&(h.setContentProcessor(SearchContentProcessor),SearchContentProcessor.reprocessExistingPosts(),
await this.processContentInPhases(e))}static async processContentInPhases(e){const t=Array.from(e.querySelectorAll(".xs3 a"))
;await SearchContentProcessor.showCachedContent(t.slice(0,8)),setTimeout(async()=>{const e=[...t.slice(0,8).filter(e=>{const t=e.closest(".pbw")
;return t&&"true"!==t.dataset.previewProcessed}),...t.slice(8)];await SearchContentProcessor.loadRemainingContent(e),await h.ensureSufficientContent()
},100)}static setupToggle(){UIComponents.createSearchPageSingleToggle({storageKeyEnabled:"searchPageInfiniteScroll",
onEnable:()=>h.enableSearchScroll(),onDisable:()=>h.disableScroll(),defaultEnabled:!0})}}function m(){try{
window.location.href.includes("search.php")?SearchPageManager.init():NormalPageManager.init()}catch(e){void 0}}window.activeRestoreButton=null,
"loading"===document.readyState?document.addEventListener("DOMContentLoaded",m):m()})();