// ==UserScript== // @name MT论坛移动端网页版增强 // @namespace https://bbs.binmt.cc/ // @version 1.0.17 // @description 在侧边栏注入 9项功能独立开关 // @match https://bbs.binmt.cc/* // @match http://bbs.binmt.cc/* // @connect bbs.binmt.cc // @connect https://bbs.binmt.cc // @connect img.binmt.cc // @connect https://img.binmt.cc // @connect icdn.binmt.cc // @connect https://icdn.binmt.cc // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @run-at document-idle // @noframes // ==/UserScript== (function () { 'use strict'; var S = { get: function(k,d){ try{var v=(typeof GM_getValue==='function')?GM_getValue(k,null):null; if(v==null)v=localStorage.getItem('mt_'+k); return (v==null)?d:v;}catch(e){return d;} }, set: function(k,v){ try{if(typeof GM_setValue==='function')GM_setValue(k,v);}catch(e){} try{localStorage.setItem('mt_'+k,v);}catch(e){} } }; var FEATS=[ {key:'autoSign',name:'自动签到',desc:'打开网页自动签到'}, {key:'urlLink',name:'URL超链接',desc:'链接自动转超链接'}, {key:'copyCode',name:'代码复制按钮',desc:'代码块一键复制'}, {key:'autoPage',name:'评论自动上下页',desc:'自动加载上下页评论'}, {key:'guideNext',name:'导读自动下一页',desc:'滚动到底自动加载'}, {key:'autoReply',name:'隐藏帖自动回复',desc:'自动回复并解锁'}, {key:'hideOnly',name:'只看隐藏贴',desc:'仅显示含隐藏内容帖',def:false}, {key:'personalBlack',name:'个人小黑屋屏蔽',desc:'按uid隐藏帖子'}, {key:'ubbBar',name:'UBB快捷输入栏',desc:'论坛输入时显示UBB代码按钮'} ]; function defOf(k){ for(var i=0;i=0;i--){ var cur=list[i]; if(cur===node||(cur.contains&&cur.contains(node)))return; if(node.contains&&node.contains(cur))list.splice(i,1); } list.push(node); } function collectMutationRoots(muts){ var out=[]; for(var i=0;i()()【】\[\]]+)/gi; for(var k=0;klast)frag.appendChild(document.createTextNode(txt.slice(last,e0))); last=e0; if(m.index===re.lastIndex)re.lastIndex++; continue; } var at=m.index+pre.length; if(at>last)frag.appendChild(document.createTextNode(txt.slice(last,at))); var a=document.createElement('a'); a.setAttribute('href',url); a.setAttribute('target','_blank'); a.setAttribute('data-mt-url','1'); a.textContent=url; a.className='mt-url-local'; frag.appendChild(a); last=m.index+m[0].length; if(m.index===re.lastIndex)re.lastIndex++; } if(last=0;i--){if(j[i].parentNode)j[i].parentNode.removeChild(j[i]);} var s=''; try{s=clone.textContent||'';}catch(e){} s=s.replace(/\u00a0/g,' '); return s.split('\n').filter(function(L){var x=L.replace(/\s/g,'');return !/^(本帖隐藏的内容|隐藏的内容|回复可见|回复后可见|登录后可见|登录可见|购买后可见|以下内容需要回复才能看到)[::]?$/.test(x);}).join('\n'); } function collectBlocks(root){ var picked=[]; function push(b){ if(!b||!b.nodeName)return; if(b.nodeName==='SCRIPT'||b.nodeName==='STYLE')return; if(b.getAttribute&&b.getAttribute('data-mt-copy')==='1')return; if(b.nodeName==='BLOCKQUOTE'||(b.closest&&b.closest('blockquote')))return; for(var k=0;k0)return p;} } else { try{var q=new URLSearchParams(location.search); var pg=q.get('page'); pg=parseInt(pg||'1',10); if(isFinite(pg)&&pg>0)return pg;}catch(e){} } var sel=document.querySelector('#dumppage'); if(sel&&sel.selectedIndex>=0)return sel.selectedIndex+1; return 1; } function totalPage(){ var sel=document.querySelector('#dumppage'); if(sel&&sel.options){return Math.max(1,sel.options.length);} var as=document.querySelectorAll('.comiis_page a'); return 1; } // ---- 构造指定页 URL(主用手段,稳定可靠) ---- // 与原页 URL 格式保持一致:伪静态用 thread-{tid}-{p}-1.html,动态用 forum.php?mod=viewthread&tid={tid}&page={p} function pageUrl(p){ if(isStatic) return 'https://bbs.binmt.cc/thread-'+st.tid+'-'+p+'-1.html'; var q=new URLSearchParams(location.search); var extra=[]; // 保留 mobile / from / 等其它参数,避免与原页不一致 for(var key of ['mobile','from','mobile2']){ if(q.get(key)) extra.push(key+'='+encodeURIComponent(q.get(key))); } var s='forum.php?mod=viewthread&tid='+encodeURIComponent(st.tid)+'&page='+p; if(extra.length)s+='&'+extra.join('&'); return new URL(s,location.origin).href; } // ---- 分页条里所有 (按顺序:上一页 / 页码select / 下一页),仅作兜底 ---- function pagerLinks(){ var box=document.querySelector(MULTI_SEL); if(!box)return []; var as=box.querySelectorAll('a.bg_f.b_ok'); var out=[]; for(var i=0;ist.total)return ''; var links=pagerLinks(); for(var i=0;i200)txt=txt.slice(0,200); return 'hash:'+txt; } function existingPids(){ var o={}; var t=target(); if(!t)return o; var ns=t.querySelectorAll(ITEM_SEL); for(var i=0;i=st.total)return; if(Date.now()-lastLoadAt0 && anchor){ var newTop=anchor.getBoundingClientRect().top+(window.pageYOffset||document.documentElement.scrollTop||0)-offset; window.scrollTo(0, newTop); } else if(inserted>0){ // 无锚点时兜底:保持原滚动位置不变(不额外跳动) window.scrollTo(0, oldScroll); } prevCool=Date.now(); // 仅成功前插后才进入冷却,避免「未加载成功却锁死」 }).catch(function(){busy=false;}); } // ---- 滚动触发 ---- var raf=null; function schedule(){ if(raf)return; raf=requestAnimationFrame(function(){ raf=null; var d=document.documentElement; var atBottom=(d.scrollHeight-d.scrollTop-d.clientHeight)<500; // 放宽顶部阈值:锚点可能把 scrollTop 停在中部,但只要列表顶距视口足够近就算「靠近顶部」 var listTopAt=(function(){ var t=target(); return t?t.getBoundingClientRect().top:Infinity; })(); var atTop=(d.scrollTop<200) || (listTopAt>-300 && listTopAt<300); var cooled=(Date.now()-prevCool)<400; // 前插后 400ms 内抑制向上加载,防止连环翻页又不过度锁死 // 独立判断(不再用 else if 互斥):靠近底部加载下一页,靠近顶部加载上一页, // 避免「锚点居中时 atBottom 吞掉向上加载」的问题 if(atBottom)loadNext(); if(atTop && !cooled)loadPrev(); }); } window.addEventListener('scroll',schedule,{passive:true}); // 补充触发点:手指/滚动停止(touchend、scroll 静止)后再判断一次, // 修复「快速滑动在顶部停留过短而错过 rAF 触发窗口」的问题 function settle(){ clearTimeout(window.__mtSettle); window.__mtSettle=setTimeout(function(){ schedule(); },120); } window.addEventListener('touchend',settle,{passive:true}); window.addEventListener('scroll',settle,{passive:true}); // 初始:若内容不足以撑满一屏,主动向下加载 setTimeout(function(){ var d=document.documentElement; if(target()&&d.scrollHeight<=d.clientHeight+500 && st.max=0)return sel.selectedIndex+1; try{ var cp=new URLSearchParams(location.search).get('page'); cp=parseInt(cp||'1',10); if(isFinite(cp)&&cp>0)return cp; }catch(e){} return 1; } function totalPage(){ var sel=document.querySelector('#dumppage'); if(sel&&sel.options)return Math.max(1,sel.options.length); return 1; } // 从 URL 解析 view 与 index 参数,用于构造分页 URL function param(k,d){ try{var v=new URLSearchParams(location.search).get(k); return v||d;}catch(e){return d;} } function qs(p){ var q=new URLSearchParams(); q.set('mod','guide'); var idx=param('index',''); if(idx)q.set('index',idx); q.set('view',param('view','newthread')); q.set('page',String(p)); return 'https://bbs.binmt.cc/forum.php?'+q.toString(); } function curList(){return document.querySelector(LIST);} // 收集当前已存在的帖子链接集合(去重键) function existingKeys(){ var o={}; var d=curList(); if(!d)return o; var ex=d.querySelectorAll(ITEM); for(var i=0;i=st.total)return; if(Date.now()-lastLoadAt60000){sessionStorage.removeItem(PK+'_'+t);return false;} return true;}catch(e){return false;} } function setPend(t,o){ try{if(o)sessionStorage.setItem(PK+'_'+t,String(Date.now()));else sessionStorage.removeItem(PK+'_'+t);}catch(e){} } function floodUntil(t){ try{var v=parseInt(localStorage.getItem(FUK+t)||'0',10);return isFinite(v)?v:0;}catch(e){return 0;} } function setFlood(t,ms){ try{if(ms>0)localStorage.setItem(FUK+t,String(Date.now()+ms));else localStorage.removeItem(FUK+t);}catch(e){} } function parseFloodWait(txt){ var s=String(txt||''); var m=s.match(/(?:少于|间隔|等待|剩余|请(?:稍候|稍后))[^\d]{0,30}(\d+)\s*秒/i); if(!m)m=s.match(/(\d+)\s*秒/i); var n=m?parseInt(m[1],10):30; if(!isFinite(n)||n<1)n=30; if(n>3600)n=3600; return n; } function submit(cb){ var f=document.getElementById('fastpostform'),mb=document.getElementById('needmessage'); if(!f||!mb){cb({ok:false,fl:false,fs:0});return;} var act=(f.getAttribute('action')||'').replace(/&/g,'&'); if(!act){cb({ok:false,fl:false,fs:0});return;} var url=act+(act.indexOf('?')>=0?'&':'?')+'handlekey=fastpost&loc=1&inajax=1'; var fd=new URLSearchParams(); fd.set('formhash',f.elements.formhash?f.elements.formhash.value:''); if(f.elements.noticeauthor)fd.set('noticeauthor',f.elements.noticeauthor.value||''); fd.set('message',rt()); fd.set('replysubmit','回复'); var x=new XMLHttpRequest(),ended=false; function finish(v){if(ended)return;ended=true;cb(v);} try{x.open('POST',url,true);x.withCredentials=true;x.setRequestHeader('Content-Type','application/x-www-form-urlencoded');x.setRequestHeader('X-Requested-With','XMLHttpRequest'); x.onreadystatechange=function(){if(x.readyState!==4)return;var txt=x.responseText||'',isFlood=/两次发表间隔少于|间隔少于\s*\d+\s*秒|请稍候再发表|请稍后再发表|灌水/i.test(txt); var ok=x.status===200&&/succeedhandle_fastpost|回复发布成功/.test(txt)&&!/errorhandle_fastpost/.test(txt)&&!isFlood; finish({ok:ok,fl:isFlood,fs:isFlood?parseFloodWait(txt):0});}; x.onerror=function(){finish({ok:false,fl:false,fs:0});}; x.ontimeout=function(){finish({ok:false,fl:false,fs:0});}; x.timeout=20000; x.send(fd.toString()); }catch(e){finish({ok:false,fl:false,fs:0});}} function viewpidHtml(t,p,cb){ var x=new XMLHttpRequest(),doneX=false; function finish(v){if(doneX)return;doneX=true;cb(v);} try{x.open('POST','forum.php?mod=viewthread&tid='+encodeURIComponent(t)+'&viewpid='+encodeURIComponent(p)+'&mobile=2',true);x.withCredentials=true; x.setRequestHeader('Content-Type','application/x-www-form-urlencoded');x.setRequestHeader('X-Requested-With','XMLHttpRequest'); x.onreadystatechange=function(){if(x.readyState!==4)return;if(x.status!==200){finish('');return;}var raw=x.responseText||'',m=raw.match(//);finish(m?m[1]:raw);}; x.onerror=function(){finish('');};x.ontimeout=function(){finish('');};x.timeout=15000;x.send(''); }catch(e){finish('');}} function replaceFloor(t,p,cb){ viewpidHtml(t,p,function(html){ if(!html||html.indexOf('id="pid'+p)<0){cb(false);return;} var tg=document.getElementById('pid'+p)||document.getElementById('post_'+p); if(!tg){cb(false);return;} try{var fr=document.createElement('div');fr.innerHTML=html;var n=fr.querySelector('#pid'+p)||fr.querySelector('#post_'+p)||fr.firstElementChild;if(!n){cb(false);return;}tg.outerHTML=n.outerHTML;cb(true);}catch(e){cb(false);}}); } function unlock(t,ps,cb){ if(!ps||!ps.length){cb(true);return;} var arr=ps.slice(),idx=0,okn=0; function one(){ if(idx>=arr.length){cb(okn===arr.length);return;} var p=arr[idx++]; replaceFloor(t,p,function(ok){if(ok)okn++; setTimeout(one,1200+Math.floor(Math.random()*1800));}); } one(); } function scheduleRun(t,ms){ clearTimeout(window.__mtarTimer); window.__mtarTimer=setTimeout(function(){setPend(t,false);run();},Math.max(1000,ms)); } function scheduleUnlock(t,ps,attempt){ clearTimeout(window.__mtarUnlockTimer); window.__mtarUnlockTimer=setTimeout(function(){if(!hasLocked())return;unlock(t,ps,function(ok){if(ok&&!hasLocked())return; if(attempt<5){scheduleUnlock(t,lockedPids(),attempt+1);}else{setTimeout(function(){if(hasLocked())location.reload();},1500);}});},attempt===0?300:Math.min(8000,1500*attempt));} function run(){ var t=tid(); if(!t||!isMobile()||!hasLocked())return; var u=uid(); if(!u||u==='0')return; var ps=lockedPids(); if(done(t)){unlock(t,ps,function(ok){if(!ok||hasLocked())scheduleUnlock(t,lockedPids(),1);});return;} if(pend(t))return; var fu=floodUntil(t),now=Date.now(); if(fu>now){scheduleRun(t,fu-now+500+Math.floor(Math.random()*1000));return;} var f=document.getElementById('fastpostform'); if(f&&(f.querySelector('[name="seccodeverify"]')||f.querySelector('[name="secqaa"]')))return; if(hasMine(u)){markDone(t);unlock(t,ps,function(ok){if(!ok||hasLocked())scheduleUnlock(t,lockedPids(),1);});return;} setPend(t,true); setTimeout(function(){try{ if(!hasLocked()){setPend(t,false);return;} var mb=document.getElementById('needmessage'); if(mb&&mb.value&&mb.value.trim()&&mb.value.trim()!==rt()){setPend(t,false);return;} var lr=parseInt(localStorage.getItem(LRK)||'0',10),since=Date.now()-lr; if(since=200&&r.status<400,r.responseText); }; r.onerror=function(){fin(false,'');}; r.ontimeout=function(){fin(false,'');}; r.send(null); }catch(e){fin(false,'');} })(Q.shift()); } } function itemOf(n){ var p=n,fb=null,d=0; while(p&&p!==document.body&&d++<10){ var tag=p.tagName||'',c=typeof p.className==='string'?p.className:'',id=p.id||''; if(/^(LI|TR|TBODY|ARTICLE)$/.test(tag)&&(/(?:^|[ _-])(?:forumlist_li|thread|topic|post)(?:[ _-]|$)/i.test(c)||/^normalthread_/i.test(id)))return p; if(!fb&&/^(LI|TR|ARTICLE)$/.test(tag))fb=p; p=p.parentElement; } return fb||n.parentElement; } function scan(root){ var links=collectScoped(root||document,'a[href*="thread-"],a[href*="mod=viewthread"]'); for(var i=0;i 黑名单)+ 本地缓存 ---- function nativeUidSet(){ var s={}; try{var v=localStorage.getItem('shieldList');if(!v)return s;var a=JSON.parse(v);if(!a)return s; if(Object.prototype.toString.call(a)!=='[object Array]')a=[a]; for(var i=0;i]*value=["']([0-9a-zA-Z]+)["']/i)||t.match(/formhash=([0-9a-zA-Z]{6,})/); if(mfh)SRV.formhash=mfh[1]; } if(!SRV.myUid){ var mm=t.match(/home\.php\?mod=space&(?:amp;)?uid=(\d+)&(?:amp;)?do=friend/i); if(mm)SRV.myUid=mm[1]; } return list; } function syncServerCache(){ var ids=[]; for(var si=0;si