// ==UserScript==
// @name gcbt-预览
// @version 1.1.3
// @namespace https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94
// @author 星宿老魔
// @description 优化国产BT列表页面样式,添加帖子图片预览和磁力链接获取功能
// @match https://gcbt.net/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gcbt.net
// @license MIT
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @connect gcbt.net
// @run-at document-start
// ==/UserScript==
(function(){"use strict";function a(x,e=[],i={}){const t=document.createElement(x);return e.length&&(t.className=e.join(" ")),Object.assign(t,i),t}function L(){return new Promise(x=>{document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>x()):x()})}const g={name:"gcbt-预览",version:"1.1.1",selectors:{postList:"article.post-list",contentArea:".content-area",entryTitle:"h2.entry-title a",metaDate:"li.meta-date time",pagination:"main .numeric-pagination",entryContent:".entry-content, .entry-wrapper, .article-content",imageSelectors:[".entry-content img",".entry-wrapper img"]},cacheTTL:1440*60*1e3,maxPreviewImages:5,concurrentLimit:15},C=class C{static init(){this.styleInjected||(this.injectStyles(),this.styleInjected=!0)}static injectStyles(){const i=a("style",[],{id:"gcbt-styles",textContent:'article.post-list{visibility:hidden}.torrent-list-container{width:100%;margin:0;padding:0}.item-container{margin-bottom:15px;border-radius:6px;overflow:hidden;border:1px solid #e1e8ed;box-shadow:0 2px 8px rgba(0,0,0,.05);background:#fff}.item-container:hover{box-shadow:0 4px 12px rgba(0,0,0,.1)}.item-title-row{padding:15px;border-bottom:1px solid #f0f0f0;border-left:4px solid #1890ff;transition:background-color .2s}.item-container:nth-child(odd) .item-title-row{background:#f8f9fa}.item-container:nth-child(even) .item-title-row{background:#f0f8ff}.item-title-row:hover{background:#f0f8ff}.item-title{font-weight:600;color:#333;font-size:15px}.item-title a{color:#333;text-decoration:none}.item-title a:hover{color:#1890ff!important}.item-preview{padding:15px;background:#fff}.item-meta-info{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;padding-bottom:10px;border-bottom:1px dashed #eaeaea}.item-date,.item-size{padding:3px 8px;border-radius:3px;font-size:12px}.item-date{background:rgba(24,144,255,.08)}.item-size{background:rgba(230,126,34,.08);color:#e67e22;font-weight:500}.item-loading{text-align:center;padding:15px;color:#666}#gcbt-image-viewer{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.85);z-index:9999;justify-content:center;align-items:center;flex-direction:column}.gcbt-viewer-close{position:absolute;top:20px;right:20px;color:white;font-size:32px;cursor:pointer;z-index:10000}.gcbt-viewer-img-container{display:flex;justify-content:center;align-items:center;height:100%;width:100%}.gcbt-viewer-img{object-fit:contain}.gcbt-nav-btn{position:absolute;top:50%;transform:translateY(-50%);color:white;font-size:36px;cursor:pointer;padding:10px;z-index:10000;user-select:none}.gcbt-nav-btn.prev{left:20px}.gcbt-nav-btn.next{right:20px}.gcbt-viewer-counter{position:absolute;bottom:20px;color:white;font-size:14px;padding:5px 10px;background:rgba(0,0,0,.5);border-radius:4px;z-index:10000}.preview-content{padding:5px}.preview-img-container{display:flex;gap:10px;justify-content:flex-start;padding:5px 0;margin:5px 0}.preview-img-wrapper{cursor:pointer;border-radius:4px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.1);transition:transform .2s;height:180px;flex:0 0 auto;position:relative}.preview-img-wrapper:hover{transform:translateY(-3px)}.preview-img{width:100%;height:100%;object-fit:cover;border-radius:3px;border:1px solid #ddd}.loading-indicator{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:12px;color:#999;z-index:1;background:rgba(255,255,255,.8);padding:4px 8px;border-radius:3px}.preview-info-container{margin-top:15px;padding-top:12px;border-top:1px dashed #e1e8ed}.action-bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.gcbt-magnet-btn{padding:5px 14px;font-size:13px;background:#409eff;color:white;border:none;border-radius:4px;cursor:pointer;box-shadow:0 2px 4px rgba(0,0,0,.1);margin:5px 0}.gcbt-magnet-btn:hover{background:#1890ff!important;box-shadow:0 2px 6px rgba(24,144,255,.2)!important}.magnet-link-container{margin:8px 0;padding:10px 12px;display:none;width:100%;background:#f0f8ff;border-radius:4px;border:1px solid #d0e1f9;font-size:13px;word-break:break-all}.magnet-link-container a{color:#1890ff;text-decoration:none}.rollbar-item.tap-dark,.navbar-button:has(.mdi-brightness-4){display:none!important}body[class*="dark"],html[class*="dark"]{background:#fff!important;color:#333!important}'});document.documentElement.appendChild(i)}static unhidePosts(){const e=document.getElementById("gcbt-styles");e&&(e.textContent=e.textContent?.replace("article.post-list { visibility: hidden; }","")||"")}};C.styleInjected=!1;let y=C;class v{static cleanPage(){document.body.classList.remove("dark","dark-mode","night-mode"),document.documentElement.classList.remove("dark","dark-mode","night-mode"),document.body.style.backgroundColor="#fff",document.body.style.color="#333"}static optimizeListPage(){const e=document.querySelectorAll(g.selectors.postList);if(!e.length)return!1;const i=a("div",["torrent-list-container"]),t=document.querySelector(g.selectors.contentArea);if(!t)return!1;e.forEach(r=>{const l=r.querySelector(g.selectors.entryTitle);if(!l)return;const c=r.querySelector(g.selectors.metaDate),d=a("a",[],{href:l.href,target:"_blank",textContent:l.textContent});d.setAttribute("data-thread-url",l.href);const s=a("div",["item-title"]);s.appendChild(d);const h=a("div",["item-title-row"]);h.appendChild(s);const f=a("span",["item-date"],{textContent:c?c.textContent?.trim().replace(/\s*前$/,""):""}),m=a("div",["item-meta-info"]);m.appendChild(f);const p=a("div",["item-preview"]);c&&p.appendChild(m),p.appendChild(a("div",["item-loading"],{textContent:"🔄 正在加载预览..."}));const u=a("div",["item-container"]);u.append(h,p),i.appendChild(u)});const n=document.querySelector("main"),o=n?n.querySelector(g.selectors.pagination):null;if(t.innerHTML="",t.appendChild(i),o){const r=o.cloneNode(!0);r.style.margin="20px 0 0 0",t.appendChild(r)}return!0}static updateTitleSize(e,i){if(!i)return;const t=e.querySelector(".item-title");if(!t)return;let n=t.querySelector(".item-size");n||(n=a("span",["item-size"]),n.style.marginLeft="10px",t.appendChild(n)),n.textContent=`【影片容量】:${i}`}}const w=class w{static init(){if(this.initialized||document.getElementById("gcbt-image-viewer"))return;const e=a("img",["gcbt-viewer-img"]),i=a("div",["gcbt-viewer-counter"]),t=a("div",["gcbt-nav-btn","prev"],{innerHTML:"❮"}),n=a("div",["gcbt-nav-btn","next"],{innerHTML:"❯"}),o=a("div",[],{id:"gcbt-image-viewer"}),r=a("div",["gcbt-viewer-img-container"]),l=a("div",["gcbt-viewer-close"],{innerHTML:"×"});r.appendChild(e),o.append(l,t,n,i,r),document.body.appendChild(o);const c=s=>{if(!this.viewerState.images.length)return;this.viewerState.currentIndex=(s+this.viewerState.images.length)%this.viewerState.images.length;const h=this.viewerState.images[this.viewerState.currentIndex];this.updateImageSize(e,h),i.textContent=`${this.viewerState.currentIndex+1} / ${this.viewerState.images.length}`;const f=this.viewerState.images.length>1;t.style.display=n.style.display=f?"block":"none"},d=()=>{o.style.display="none",document.body.style.overflow=""};e.addEventListener("click",s=>s.stopPropagation()),l.addEventListener("click",d),o.addEventListener("click",d),t.addEventListener("click",s=>{s.stopPropagation(),c(this.viewerState.currentIndex-1)}),n.addEventListener("click",s=>{s.stopPropagation(),c(this.viewerState.currentIndex+1)}),document.addEventListener("keydown",s=>{o.style.display!=="none"&&(s.key==="Escape"?d():s.key==="ArrowLeft"?c(this.viewerState.currentIndex-1):s.key==="ArrowRight"&&c(this.viewerState.currentIndex+1))}),this.initialized=!0}static show(e,i=0){this.initialized||this.init(),this.viewerState.images=e,this.viewerState.currentIndex=i;const t=document.getElementById("gcbt-image-viewer"),n=document.querySelector(".gcbt-viewer-img"),o=document.querySelector(".gcbt-viewer-counter"),r=document.querySelector(".gcbt-nav-btn.prev"),l=document.querySelector(".gcbt-nav-btn.next");if(t&&n&&o&&r&&l){t.style.display="flex",document.body.style.overflow="hidden";const c=e[i];this.updateImageSize(n,c),o.textContent=`${i+1} / ${e.length}`;const d=e.length>1;r.style.display=l.style.display=d?"block":"none"}}static updateImageSize(e,i){e.style.width="",e.style.height="",e.style.maxWidth="",e.style.maxHeight="",e.style.display="none",e.onload=()=>{e.style.display="block";const t=window.innerWidth*.9,n=window.innerHeight*.9,o=e.naturalWidth,r=e.naturalHeight;if(o<300&&r<300){const l=o*2,c=r*2;l<=t&&c<=n?(e.style.width=l+"px",e.style.height=c+"px"):this.scaleImageToFit(e,l,c,t,n)}else o>t||r>n?this.scaleImageToFit(e,o,r,t,n):(e.style.width=o+"px",e.style.height=r+"px")},e.onerror=()=>{e.style.display="block",e.textContent="图片加载失败"},e.src=i}static scaleImageToFit(e,i,t,n,o){const r=n/i,l=o/t,c=Math.min(r,l),d=i*c,s=t*c;e.style.width=d+"px",e.style.height=s+"px"}};w.initialized=!1,w.viewerState={images:[],currentIndex:0};let b=w;class k{static fetchPage(e){return new Promise((i,t)=>{GM_xmlhttpRequest({method:"GET",url:e,onload:n=>{if(n.status>=200&&n.status<300){const o=new DOMParser().parseFromString(n.responseText,"text/html");i(o)}else t(new Error(`请求失败,状态码: ${n.status}`))},onerror:n=>t(n),ontimeout:()=>t(new Error("请求超时"))})})}static async fetchMagnetLink(e){const t=(await this.fetchPage(e)).body.innerHTML;let n=t.match(/(magnet:\?xt=urn:btih:[a-f0-9]{40})/i);if(n)return n[0];const o=t.match(/(?:^|:|:|;|;|】|\])\s*([0-9a-zA-Z]{40})/i);return o?`magnet:?xt=urn:btih:${o[1]}`:null}}class T{static async processAll(){const e=document.querySelectorAll(".torrent-list-container a[data-thread-url]"),i=[],t=[];e.forEach(o=>{const r=o.closest(".item-container");r&&this.isInViewport(r)?i.push(o):t.push(o)});const n=Math.min(g.concurrentLimit,i.length);for(let o=0;o<i.length;o+=n){const r=i.slice(o,o+n);Promise.all(r.map(l=>this.processSingle(l)))}t.length>0&&setTimeout(()=>{const o=g.concurrentLimit;for(let r=0;r<t.length;r+=o){const l=t.slice(r,r+o);setTimeout(()=>{Promise.all(l.map(c=>this.processSingle(c)))},Math.floor(r/o)*100)}},100)}static isInViewport(e){const i=e.getBoundingClientRect();return i.top<window.innerHeight&&i.bottom>0}static async processSingle(e){const i=e.closest(".item-container"),t=i?.querySelector(".item-preview");if(!t)return;const n=e.href;let o=GM_getValue(n)||{};const r=Date.now(),l=!o.cacheTimestamp||r-o.cacheTimestamp>g.cacheTTL;try{if(l){const c=await k.fetchPage(n),d={cacheTimestamp:r},s=Array.from(c.querySelectorAll(g.selectors.imageSelectors.join(","))).slice(0,g.maxPreviewImages);d.imgUrls=s.map(p=>p.src||p.getAttribute("data-src")).filter(Boolean);const m=(c.querySelector(g.selectors.entryContent)?.textContent||"").match(/【影片(?:大小|容量)】:([0-9.]+\s*(?:MB|GB|M|G|T|TB))/i);m?.[1]&&(d.filmSize=m[1]),GM_setValue(n,d),o=d}this.renderPreview(t,i,o,n)}catch(c){t.innerHTML="加载预览失败",t.className="item-loading",t.style.color="#f56c6c",console.error("加载预览失败",c)}}static renderPreview(e,i,t,n){if(e.innerHTML="",!t.imgUrls||t.imgUrls.length===0){e.textContent="没有找到预览图片";return}const o=a("div",["preview-content"]),r=a("div",["preview-img-container"]);t.imgUrls.forEach((h,f)=>{const m=a("div",["preview-img-wrapper"]),p=a("img",["preview-img"]);m.style.backgroundColor="#f5f5f5",m.style.position="relative";const u=a("div",["loading-indicator"]);u.textContent="加载中...",u.style.cssText="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 12px; color: #999; z-index: 1;",m.appendChild(u),p.style.opacity="0",p.style.transition="opacity 0.3s ease",this.preloadImageDNS(h),p.onload=()=>{p.style.opacity="1",u.remove(),m.style.backgroundColor=""},p.onerror=()=>{u.textContent="加载失败",u.style.color="#f56c6c",setTimeout(()=>{m.style.display="none"},1500)},this.preloadImage(h).then(()=>{p.src=h}).catch(()=>{p.src=h}),m.appendChild(p),m.addEventListener("click",S=>{S.preventDefault(),S.stopPropagation(),b.show(t.imgUrls,f)}),r.appendChild(m)}),r.children.length>0&&this.setImageGridWidth(r,r.children.length),o.appendChild(r);const l=a("div",["preview-info-container"]),c=a("div",["action-bar"]),d=a("button",["gcbt-magnet-btn"]);c.appendChild(d);const s=a("div",["magnet-link-container"]);l.append(c,s),o.appendChild(l),e.appendChild(o),d.addEventListener("click",async h=>{h.preventDefault(),h.stopPropagation(),d.textContent="正在获取...",d.disabled=!0,s.innerHTML="",s.style.display="none";try{const f=await k.fetchMagnetLink(n);f?(t.link=f,GM_setValue(n,t),this.displayMagnetLink(s,f)):(s.textContent="未找到有效链接",s.style.display="block",s.style.color="#f56c6c")}catch(f){console.error("获取磁力失败",f),s.textContent="获取失败",s.style.display="block",s.style.color="#f56c6c"}finally{d.textContent="重新获取",d.disabled=!1}}),t.link?(this.displayMagnetLink(s,t.link),d.textContent="重新获取"):d.textContent="获取磁力链接",t.filmSize&&v.updateTitleSize(i,t.filmSize)}static displayMagnetLink(e,i){e.innerHTML="";const t=a("a",[],{href:i,textContent:i});i.startsWith("magnet:")?(t.style.cursor="pointer",t.title="点击复制磁力链接",t.addEventListener("click",n=>{n.preventDefault(),navigator.clipboard.writeText(i).then(()=>{const o=t.textContent;t.textContent="已复制!",t.style.color="#52c41a",setTimeout(()=>{t.textContent=o,t.style.color="#1890ff"},2e3)})})):t.target="_blank",e.appendChild(t),e.style.display="block"}static preloadImage(e){return new Promise((i,t)=>{const n=new Image;n.onload=()=>i(),n.onerror=()=>t(),n.src=e})}static preloadImageDNS(e){try{const t=new URL(e).hostname;if(!document.querySelector(`link[rel="dns-prefetch"][href="//${t}"]`)){const n=a("link",[],{rel:"dns-prefetch",href:`//${t}`});document.head.appendChild(n)}}catch{}}static setImageGridWidth(e,i){let t;i===1?t="50%":t=`calc((100% - ${(i-1)*10}px) / ${i})`,Array.from(e.children).forEach(n=>{n.style.width=t,n.style.flex="0 0 auto"})}}class z{static async run(){console.log("gcbt启动"),y.init(),await L();try{v.cleanPage(),document.querySelector(g.selectors.postList)&&v.optimizeListPage()&&(b.init(),await T.processAll())}catch(e){console.error("脚本执行失败",e)}finally{y.unhidePosts()}}}z.run()})();