// ==UserScript== // @name MT论坛移动端网页版增强 // @namespace https://bbs.binmt.cc/ // @version 1.0.11 // @description 在侧边栏注入 9项功能独立开关 // @match https://bbs.binmt.cc/* // @match http://bbs.binmt.cc/* // @connect img.binmt.cc // @connect https://img.binmt.cc // @connect icdn.binmt.cc // @connect https://icdn.binmt.cc // @connect * // @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隐藏帖子',def:false}, {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;k=0?'':h; } var ns=document.querySelectorAll('a.bg_f.b_ok'); n=ns[ns.length-1]; return n?n.getAttribute('href')||'':''; } function loadNext(){ if(req)return; var u=nextUrl(); if(!u||u.indexOf('javascript')>=0)return; req=true; fetch(u,{credentials:'include'}).then(function(r){return r.text();}).then(function(html){ req=false; var tmp=document.createElement('div'); tmp.innerHTML=html; var items=tmp.querySelectorAll('.comiis_postli.comiis_list_readimgs.nfqsqi'); var target=document.querySelector('.comiis_postlist.kqide'); var bs=tmp.querySelector('.comiis_multi_box.bg_f.b_t.b_b.mb10'); if(bs){ var bd=document.querySelector('.comiis_multi_box.bg_f.b_t.b_b.mb10'); if(bd)bd.replaceWith(bs); } if(target&&items.length){ for(var i=0;i0)st.page=cp; }catch(e){} function curList(){return document.querySelector(LIST);} function curView(){try{return new URLSearchParams(location.search).get('view')||'newthread';}catch(e){return 'newthread';}} function nextPageUrl(){ return 'https://bbs.binmt.cc/forum.php?mod=guide&view='+curView()+'&page='+(st.page+1); } function loadNext(){ if(st.loading||st.ended)return; var d=curList(); if(!d)return; st.loading=true; fetch(nextPageUrl(),{credentials:'include'}).then(function(r){return r.text();}).then(function(html){ st.loading=false; var tmp=document.createElement('div'); tmp.innerHTML=html; var src=tmp.querySelector(LIST); var items=src?src.querySelectorAll(ITEM):[]; var d2=curList(); if(!d2||!items.length){st.ended=true;return;} var seen={}; var ex=d2.querySelectorAll(ITEM); for(var i=0;i60000){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 left=ps.length,okn=0; for(var i=0;inow){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]*class=["']?[^"'>]*\bb_t\b[^"'>]*["']?[^>]*>([\s\S]*?)<\/li>/gi; var bm; while((bm=reBlock.exec(t))){ var block=bm[1]||'',uid='',name=''; var mTit=block.match(/]*class=["']?[^"'>]*\btit\b[^"'>]*["']?[^>]*>[\s\S]*?]*href=["'][^"']*\buid=(\d+)[^"']*\bdo=profile[^"']*["'][^>]*>([\s\S]*?)<\/a>/i)||block.match(/]*class=["']?[^"'>]*\btit\b[^"'>]*["']?[^>]*>[\s\S]*?]*href=["'][^"']*\bdo=profile[^"']*\buid=(\d+)[^"']*["'][^>]*>([\s\S]*?)<\/a>/i); if(mTit){ uid=mTit[1]; name=String(mTit[2]||'').replace(/<[^>]*>/g,'').replace(/ /g,' ').trim(); } if(!uid){ var mDel=block.match(/href=["'][^"']*subop=delete[^"']*\buid=(\d+)[^"']*["']/i)||block.match(/href=["'][^"']*\buid=(\d+)[^"']*subop=delete[^"']*["']/i); if(mDel)uid=mDel[1]; if(!uid){ var mProf=block.match(/href=["'][^"']*\buid=(\d+)[^"']*\bdo=profile[^"']*["']/i); if(mProf)uid=mProf[1]; } } if(uid&&!seen[uid]){ seen[uid]=1; list.push({uid:uid,user:name,_server:true}); } } if(!list.length){ var reTit=/]*class=["']?[^"'>]*\btit\b[^"'>]*["']?[^>]*>[\s\S]*?]*href=["'][^"']*\buid=(\d+)[^"']*\bdo=profile[^"']*["'][^>]*>([\s\S]*?)<\/a>/gi; var m2; while((m2=reTit.exec(t))){ var u2=m2[1]; if(!seen[u2]){ seen[u2]=1; list.push({uid:u2,user:String(m2[2]||'').replace(/<[^>]*>/g,'').trim(),_server:true}); } } } if(!SRV.formhash){ var mfh=t.match(/name=["']?formhash["']?[^>]*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;si604800000){ if(!window.__mtFetching){ window.__mtFetching=1; fetchServer(function(){ window.__mtFetching=0; schedule(document.body||document.documentElement); }); } } }catch(e){} } function serverUidSet(){ var s={}; try{var v=localStorage.getItem(SKEY); if(v){var a=JSON.parse(v); if(a&&Object.prototype.toString.call(a)==='[object Array]'){for(var i=0;ia){ var s=ta.value.substring(a,b); if(s)return s; } } var w=window.getSelection&&window.getSelection(); if(w&&w.toString)return w.toString(); return ''; }catch(e){ return ''; } } function ubbChangeText(id,a,b){ try{ var ta=document.getElementById(id); if(!ta)return; var st=(typeof ta.selectionStart==='number')?ta.selectionStart:ta.value.length; var fn=(typeof ta.selectionEnd==='number')?ta.selectionEnd:ta.value.length; if(st>fn){var t=st;st=fn;fn=t;} var all=ta.value,sel=all.substring(st,fn); var nt; if(b)nt=all.substring(0,st)+a+sel+b+all.substring(fn,all.length); else nt=all.substring(0,st)+a+all.substring(fn,all.length); ta.value=nt; var cur=st+a.length+sel.length+(b?b.length:0); try{ta.selectionStart=ta.selectionEnd=cur;ta.focus();}catch(e){} }catch(e){} } // ========== 图片上传(MT论坛图床 img.binmt.cc)========== function mtImageInsert(url){ try{ var ta=document.getElementById('needmessage'); if(!ta)return; var tag='[img]'+url+'[/img]'; var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage',tag,''); } else{ ubbInsertText(ta,tag); } }catch(e){} } function mtImageInsertLink(url){ try{ var ta=document.getElementById('needmessage'); if(!ta)return; var tag='[url='+url+'][img]'+url+'[/img][/url]\n'; var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage',tag,''); } else{ ubbInsertText(ta,tag); } }catch(e){} } function mtImageInsertLink2(imgUrl,linkUrl){ try{ var ta=document.getElementById('needmessage'); if(!ta)return; var tag='[url='+linkUrl+'][img]'+imgUrl+'[/img][/url]\n'; var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage',tag,''); } else{ ubbInsertText(ta,tag); } }catch(e){} } function mtImageStyle(){ if(document.getElementById('mt-img-style'))return; var st=document.createElement('style'); st.id='mt-img-style'; st.textContent='@keyframes mtfade{from{opacity:0}to{opacity:1}}@keyframes mtscale{from{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}'+ '#mt-img-mask{position:fixed;left:0;top:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:2147483000;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box;animation:mtfade .18s ease;}'+ '#mt-img-box{width:100%;max-width:320px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.22),0 2px 8px rgba(0,0,0,.08);animation:mtscale .18s ease;}'+ '#mt-img-title{font-size:17px;font-weight:600;color:#1a1a1a;padding:22px 22px 0;}'+ '#mt-img-sub{font-size:12px;color:#999;padding:4px 22px 12px;word-break:break-all;}'+ '#mt-img-body{padding:0 22px 10px;}'+ '#mt-img-url{width:100%;box-sizing:border-box;padding:10px 2px;border:none;border-bottom:1.5px solid #e0e2e6;border-radius:0;font-size:16px;color:#16181d;background:transparent;outline:none;transition:border-color .18s;}'+ '#mt-img-url::placeholder{color:#b0b5bc;font-size:15px;}'+ '#mt-img-url:hover{border-bottom-color:#cdd1d6;}'+ '#mt-img-url:focus{border-bottom-color:#3a76f0;}'+ '#mt-img-link{width:100%;box-sizing:border-box;padding:10px 2px;border:none;border-bottom:1.5px solid #e0e2e6;border-radius:0;font-size:14px;color:#16181d;background:transparent;outline:none;transition:border-color .18s;margin-top:10px;}'+ '#mt-img-link::placeholder{color:#b0b5bc;font-size:13px;}'+ '#mt-img-link:hover{border-bottom-color:#cdd1d6;}'+ '#mt-img-link:focus{border-bottom-color:#3a76f0;}'+ '#mt-img-actions{display:flex;justify-content:flex-end;align-items:center;padding:4px 14px 14px;gap:6px;}'+ '#mt-img-actions .mb{min-width:56px;padding:10px 14px;border:none;background:none;font-size:15px;font-weight:500;letter-spacing:.2px;text-align:center;cursor:pointer;color:#6b7280;border-radius:8px;transition:background .15s;}'+ '#mt-img-actions .mb.primary{color:#3a76f0;font-weight:600;}'+ '#mt-img-actions .mb:active{background:#eef1f6;}'+ '#mt-img-actions .mb:hover{background:#f3f5f9;}'+ '#mt-img-file{display:none;}'+ '#mt-img-msg{font-size:12px;color:#f0433f;padding:0 22px 4px;min-height:16px;}'; (document.head||document.documentElement).appendChild(st); } function mtRainbowApply(){ try{ var t=ubbSelText(); if(!t){ alert('请选中一段文字'); return; } // 精确移植 APP 原生 set_rainbow 彩虹渐变算法(红→黄→绿→青→蓝→品红 循环,步长40,空格跳过) var r=255,g=0,b=0,i=1,j=0,istep=40,out=''; function hex(v){ var s=parseInt(v).toString(16); return s.length===1?'0'+s:s; } var n=t.length; for(var k=0;k-1){ if(i===2)r-=istep; } else if(i===2){ i=3; r=0; } if(b+istep<256){ if(i===3)b+=istep; } else if(i===3){ i=4; b=255; } if(g-istep>-1){ if(i===4)g-=istep; } else if(i===4){ i=5; g=0; } if(r+istep<256){ if(i===5)r+=istep; } else if(i===5){ i=6; r=255; } if(b-istep>-1){ if(i===6)b-=istep; } else if(i===6){ i=1; b=0; } out+='[color=#'+(hex(r)+hex(g)+hex(b)).toUpperCase()+']'+ch+'[/color]'; } else { out+=ch; } } ubbChangeText('needmessage',out,''); }catch(e){} } function mtColorStyle(){ if(document.getElementById('mt-color-style'))return; var st=document.createElement('style'); st.id='mt-color-style'; st.textContent='@keyframes mtfade{from{opacity:0}to{opacity:1}}@keyframes mtscale{from{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}'+ '#mt-color-mask{position:fixed;left:0;top:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:2147483001;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box;animation:mtfade .18s ease;}'+ '#mt-color-box{width:100%;max-width:320px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.22),0 2px 8px rgba(0,0,0,.08);animation:mtscale .18s ease;}'+ '#mt-color-title{font-size:17px;font-weight:600;color:#1a1a1a;padding:22px 22px 0;}'+ '#mt-color-prev{display:flex;align-items:center;gap:12px;padding:14px 22px 12px;}'+ '#mt-color-prev .sw{width:42px;height:42px;border-radius:10px;border:1px solid rgba(0,0,0,.12);background:#000;box-shadow:inset 0 1px 2px rgba(0,0,0,.08);}'+ '#mt-color-prev .hex{font-size:16px;font-family:monospace;color:#1a1a1a;letter-spacing:.5px;}'+ '.mt-color-row{display:flex;align-items:center;gap:10px;padding:5px 22px;}'+ '.mt-color-row .lb{width:14px;font-size:13px;font-weight:600;color:#555;}'+ '.mt-color-row .vx{width:30px;font-size:12px;color:#999;font-family:monospace;text-align:right;}'+ '.mt-color-row input[type=range]{flex:1;height:24px;accent-color:#3a76f0;}'+ '#mt-color-actions{display:flex;justify-content:flex-end;align-items:center;padding:14px 14px;gap:6px;}'+ '#mt-color-actions .mb{min-width:56px;padding:10px 14px;border:none;background:none;font-size:15px;font-weight:500;letter-spacing:.2px;text-align:center;cursor:pointer;color:#6b7280;border-radius:8px;transition:background .15s;}'+ '#mt-color-actions .mb.primary{color:#3a76f0;font-weight:600;}'+ '#mt-color-actions .mb:active{background:#eef1f6;}'+ '#mt-color-actions .mb:hover{background:#f3f5f9;}'; (document.head||document.documentElement).appendChild(st); } function mtColorDialog(){ try{ mtColorStyle(); if(document.getElementById('mt-color-mask'))return; var r=0,g=0,b=0; // 初始黑 #000000(同 APP 原生 progress=1) function hex(v){ var s=parseInt(v).toString(16); return s.length===1?'0'+s:s; } function rgb(){ return '#'+(hex(r)+hex(g)+hex(b)).toUpperCase(); } var mask=document.createElement('div'); mask.id='mt-color-mask'; var box=document.createElement('div'); box.id='mt-color-box'; var title=document.createElement('div'); title.id='mt-color-title'; title.textContent='选色器'; // 预览 var prev=document.createElement('div'); prev.id='mt-color-prev'; var sw=document.createElement('div'); sw.className='sw'; var hexEl=document.createElement('span'); hexEl.className='hex'; hexEl.textContent='#000000'; prev.appendChild(sw); prev.appendChild(hexEl); // 三个 RGB 滑条 function mkRow(lb){ var row=document.createElement('div'); row.className='mt-color-row'; var l=document.createElement('span'); l.className='lb'; l.textContent=lb; var s=document.createElement('input'); s.type='range'; s.min='0'; s.max='255'; s.value='0'; var v=document.createElement('span'); v.className='vx'; v.textContent='00'; row.appendChild(l); row.appendChild(s); row.appendChild(v); return {row:row,s:s,v:v}; } var R=mkRow('R'),G=mkRow('G'),B=mkRow('B'); function refresh(){ sw.style.background=rgb(); hexEl.textContent=rgb(); } function bind(X){ X.s.addEventListener('input',function(){ var val=parseInt(X.s.value)||0; if(X===R)r=val;else if(X===G)g=val;else b=val; X.v.textContent=hex(val).toUpperCase(); refresh(); }); } bind(R);bind(G);bind(B); // 快捷取色 input color var cbtn=document.createElement('input'); cbtn.type='color'; cbtn.value='#000000'; cbtn.style.cssText='margin:0 16px 8px;width:56px;height:32px;border:none;background:none;cursor:pointer;padding:0;'; cbtn.addEventListener('input',function(){ var c=cbtn.value.replace('#',''); r=parseInt(c.substr(0,2),16)||0; g=parseInt(c.substr(2,2),16)||0; b=parseInt(c.substr(4,2),16)||0; R.s.value=r;G.s.value=g;B.s.value=b; R.v.textContent=hex(r).toUpperCase();G.v.textContent=hex(g).toUpperCase();B.v.textContent=hex(b).toUpperCase(); refresh(); }); // 按钮 var actions=document.createElement('div'); actions.id='mt-color-actions'; var cb=document.createElement('div'); cb.className='mb'; cb.textContent='取消'; var ob=document.createElement('div'); ob.className='mb primary'; ob.textContent='确定'; function apply(){ try{ var col=rgb(); var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage','[color='+col+']','[/color]'); } else { var ta=document.getElementById('needmessage'); ubbInsertText(ta,'[color='+col+'][/color]'); } }catch(e){} finally{ try{mask.remove();}catch(e){} } } ob.addEventListener('click',apply); cb.addEventListener('click',function(){ try{mask.remove();}catch(e){} }); actions.appendChild(cb); actions.appendChild(ob); box.appendChild(title); box.appendChild(prev); box.appendChild(R.row); box.appendChild(G.row); box.appendChild(B.row); box.appendChild(cbtn); box.appendChild(actions); mask.appendChild(box); mask.addEventListener('click',function(e){ if(e.target===mask){ try{mask.remove();}catch(err){} } }); (document.body||document.documentElement).appendChild(mask); }catch(e){} } function mtDialogStyle(){ if(document.getElementById('mt-dlg-style'))return; var st=document.createElement('style'); st.id='mt-dlg-style'; st.textContent='#mt-dlg-mask{position:fixed;left:0;top:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:2147483002;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box;animation:mtfade .18s ease;}'+ '@keyframes mtfade{from{opacity:0}to{opacity:1}}'+ '#mt-dlg-box{width:100%;max-width:320px;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.22),0 2px 8px rgba(0,0,0,.08);animation:mtscale .18s ease;}'+ '@keyframes mtscale{from{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}'+ '#mt-dlg-title{font-size:19px;font-weight:600;line-height:1.4;color:#16181d;padding:28px 28px 0;letter-spacing:.2px;}'+ '#mt-dlg-body{padding:22px 28px 0;}'+ '.mt-dlg-field{margin-bottom:22px;}'+ '.mt-dlg-field .lb{display:block;font-size:14px;font-weight:500;color:#3a3f47;margin-bottom:10px;letter-spacing:.2px;}'+ '.mt-dlg-field .lb .st{color:#f0433f;margin-right:3px;font-weight:600;}'+ '.mt-dlg-field input{width:100%;height:40px;padding:0 2px;border:none;border-bottom:1.5px solid #e0e2e6;border-radius:0;font-size:16px;color:#16181d;background:transparent;box-sizing:border-box;outline:none;transition:border-color .18s;}'+ '.mt-dlg-field input::placeholder{color:#b0b5bc;font-size:15px;}'+ '.mt-dlg-field input:hover{border-bottom-color:#cdd1d6;}'+ '.mt-dlg-field input:focus{border-bottom-color:#3a76f0;}'+ '#mt-dlg-msg{font-size:13px;color:#f0433f;padding:0 28px 0;min-height:20px;margin-top:-12px;margin-bottom:10px;}'+ '#mt-dlg-actions{display:flex;justify-content:flex-end;align-items:center;padding:6px 18px 18px;gap:8px;}'+ '#mt-dlg-actions .mb{min-width:60px;padding:11px 16px;border:none;background:none;font-size:15px;font-weight:500;letter-spacing:.3px;text-align:center;cursor:pointer;color:#6b7280;border-radius:10px;transition:background .15s;}'+ '#mt-dlg-actions .mb.primary{color:#3a76f0;font-weight:600;}'+ '#mt-dlg-actions .mb:active{background:#eef1f6;}'+ '#mt-dlg-actions .mb:hover{background:#f3f5f9;}'; (document.head||document.documentElement).appendChild(st); } function mtDialogShell(title){ try{ mtDialogStyle(); var mask=document.createElement('div'); mask.id='mt-dlg-mask'; var box=document.createElement('div'); box.id='mt-dlg-box'; var t=document.createElement('div'); t.id='mt-dlg-title'; t.textContent=title; var body=document.createElement('div'); body.id='mt-dlg-body'; var msg=document.createElement('div'); msg.id='mt-dlg-msg'; box.appendChild(t); box.appendChild(body); box.appendChild(msg); mask.appendChild(box); mask.addEventListener('click',function(e){ if(e.target===mask){ try{mask.remove();}catch(err){} } }); (document.body||document.documentElement).appendChild(mask); return {mask:mask,body:body,msg:msg,close:function(){try{mask.remove();}catch(e){}}}; }catch(e){ return null; } } function mtDlgField(body,label,required,placeholder){ try{ var f=document.createElement('div'); f.className='mt-dlg-field'; var l=document.createElement('label'); l.className='lb'; if(required){ var st=document.createElement('span'); st.className='st'; st.textContent='*'; l.appendChild(st); } l.appendChild(document.createTextNode(label)); var inp=document.createElement('input'); inp.type='text'; if(placeholder)inp.placeholder=placeholder; f.appendChild(l); f.appendChild(inp); body.appendChild(f); return inp; }catch(e){ return null; } } // URL / Email 超链接:双输入弹窗(地址必填,名称选填,空则沿用地址) function mtLinkDialog(kind){ try{ var isUrl=(kind==='URL'); var sh=mtDialogShell(isUrl?'插入链接':'插入邮箱链接'); if(!sh)return; var url=mtDlgField(sh.body,isUrl?'链接地址':'邮箱地址',true,isUrl?'https://example.com':'name@example.com'); var name=mtDlgField(sh.body,'显示文本',false,'留空则显示地址本身'); var actions=document.createElement('div'); actions.id='mt-dlg-actions'; var cb=document.createElement('div'); cb.className='mb'; cb.textContent='取消'; var ob=document.createElement('div'); ob.className='mb primary'; ob.textContent='确定'; function ok(){ try{ var u=(url.value||'').trim(); if(!u){ sh.msg.textContent=(isUrl?'链接地址':'邮箱地址')+'不能为空'; try{url.focus();}catch(e){} return; } var nm=(name.value||'').trim(); if(!nm)nm=u; var tag=(isUrl?'[url=':'[email=')+u+']'+nm+(isUrl?'[/url]':'[/email]')+'\n'; var ta=document.getElementById('needmessage'); ubbInsertText(ta,tag); sh.close(); }catch(e){} } ob.addEventListener('click',ok); url.addEventListener('keydown',function(e){ if(e.key==='Enter')ok(); }); name.addEventListener('keydown',function(e){ if(e.key==='Enter')ok(); }); cb.addEventListener('click',function(){ sh.close(); }); actions.appendChild(cb); actions.appendChild(ob); sh.body.appendChild(actions); }catch(e){} } // 字号文字:1~9 弹窗 function mtSizeDialog(){ try{ var sh=mtDialogShell('文字大小'); if(!sh)return; var f=document.createElement('div'); f.className='mt-dlg-field'; var l=document.createElement('span'); l.className='lb'; l.textContent='大小'; var inp=document.createElement('input'); inp.type='number'; inp.min='1'; inp.max='9'; inp.value='3'; inp.placeholder='1~9'; f.appendChild(l); f.appendChild(inp); sh.body.appendChild(f); var hint=document.createElement('div'); hint.style.cssText='font-size:12px;color:#999;padding:2px 0;'; hint.textContent='文字大小可选 1~9'; sh.body.appendChild(hint); var actions=document.createElement('div'); actions.id='mt-dlg-actions'; var cb=document.createElement('div'); cb.className='mb'; cb.textContent='取消'; var ob=document.createElement('div'); ob.className='mb primary'; ob.textContent='确定'; function apply(v){ try{ var s=String(v); var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage','[size='+s+']','[/size]'); } else { var ta=document.getElementById('needmessage'); ubbInsertText(ta,'[size='+s+'][/size]'); } }catch(e){} sh.close(); } function ok(){ var v=parseInt(inp.value); if(!v||v<1||v>9){ sh.msg.textContent='请输入 1~9 之间的数字'; return; } apply(v); } ob.addEventListener('click',ok); inp.addEventListener('keydown',function(e){ if(e.key==='Enter')ok(); }); cb.addEventListener('click',function(){ sh.close(); }); actions.appendChild(cb); actions.appendChild(ob); sh.body.appendChild(actions); }catch(e){} } // 对齐文本:居左/居中/居右 三选项 function mtAlignMenu(){ try{ var sh=mtDialogShell('对齐文本'); if(!sh)return; var opts=[['left','居左'],['center','居中'],['right','居右']]; var wrap=document.createElement('div'); wrap.id='mt-dlg-actions'; wrap.style.cssText='margin:4px 0 8px;'; function apply(v){ try{ var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage','[align='+v+']','[/align]'); } else { var ta=document.getElementById('needmessage'); ubbInsertText(ta,'[align='+v+'][/align]'); } }catch(e){} sh.close(); } opts.forEach(function(o){ var b=document.createElement('div'); b.className='mb primary'; b.textContent=o[1]; b.addEventListener('click',function(){ apply(o[0]); }); wrap.appendChild(b); }); var cb=document.createElement('div'); cb.className='mb'; cb.textContent='取消'; cb.addEventListener('click',function(){ sh.close(); }); wrap.appendChild(cb); sh.body.appendChild(wrap); }catch(e){} } // 网络视频:视频地址弹窗 function mtMediaDialog(){ try{ var sh=mtDialogShell('网络视频'); if(!sh)return; var url=mtDlgField(sh.body,'视频地址',true,'视频链接或地址'); var actions=document.createElement('div'); actions.id='mt-dlg-actions'; var cb=document.createElement('div'); cb.className='mb'; cb.textContent='取消'; var ob=document.createElement('div'); ob.className='mb primary'; ob.textContent='确定'; function ok(){ try{ var u=(url.value||'').trim(); if(!u){ sh.msg.textContent='视频地址不可为空'; return; } var sel=ubbSelText(); if(sel){ ubbChangeText('needmessage','[media=x,500,375]'+u+'[/media]',''); } else { var ta=document.getElementById('needmessage'); ubbInsertText(ta,'[media=x,500,375]'+u+'[/media]'); } sh.close(); }catch(e){} } ob.addEventListener('click',ok); url.addEventListener('keydown',function(e){ if(e.key==='Enter')ok(); }); cb.addEventListener('click',function(){ sh.close(); }); actions.appendChild(cb); actions.appendChild(ob); sh.body.appendChild(actions); }catch(e){} } function mtImageDialog(){ mtImageStyle(); if(document.getElementById('mt-img-mask')){ return; } var mask=document.createElement('div'); mask.id='mt-img-mask'; var box=document.createElement('div'); box.id='mt-img-box'; var title=document.createElement('div'); title.id='mt-img-title'; title.textContent='网络图片'; var sub=document.createElement('div'); sub.id='mt-img-sub'; sub.textContent='上传到MT论坛图床 或 手动输入链接'; var body=document.createElement('div'); body.id='mt-img-body'; var url=document.createElement('input'); url.id='mt-img-url'; url.type='text'; url.placeholder='也可直接粘贴图片链接'; var msg=document.createElement('div'); msg.id='mt-img-msg'; var actions=document.createElement('div'); actions.id='mt-img-actions'; var fbtn=document.createElement('label'); fbtn.className='mb'; fbtn.textContent='上传图片'; var finp=document.createElement('input'); finp.id='mt-img-file'; finp.type='file'; finp.accept='image/*'; fbtn.appendChild(finp); // 自定义点击跳转链接(可选) var link=document.createElement('input'); link.id='mt-img-link'; link.type='text'; link.placeholder='点击图片打开链接(可选,留空不添加)'; var ibtn=document.createElement('div'); ibtn.className='mb primary'; ibtn.textContent='插入'; var cbtn=document.createElement('div'); cbtn.className='mb'; cbtn.textContent='取消'; actions.appendChild(fbtn); actions.appendChild(ibtn); actions.appendChild(cbtn); body.appendChild(url); body.appendChild(link); box.appendChild(title); box.appendChild(sub); box.appendChild(body); box.appendChild(msg); box.appendChild(actions); mask.appendChild(box); document.body.appendChild(mask); function close(){ try{ mask.parentNode.removeChild(mask); }catch(e){} } mask.addEventListener('click',function(e){ if(e.target===mask)close(); }); cbtn.addEventListener('click',close); ibtn.addEventListener('click',function(){ var v=(url.value||'').trim(); if(v){ var linkUrl=(link.value||'').trim(); if(linkUrl){ mtImageInsertLink2(v,linkUrl); } else{ mtImageInsert(v); } close(); } else{ msg.textContent='请先上传图片或输入链接'; } }); finp.addEventListener('change',function(){ var f=finp.files&&finp.files[0]; if(!f)return; msg.textContent='上传中...'; if(!/^image\//i.test(f.type)){ msg.textContent='请选择图片文件'; return; } mtImageUpload(f,function(ok,res){ if(ok&&res){ url.value=res; msg.textContent='上传成功,点击「插入」写入输入框'; } else{ msg.textContent=res||'上传失败,请重试'; } }); }); } // ========== 图片上传(优先:论坛同源 swfupload;降级:MT论坛图床 img.binmt.cc)========== // 主入口:先走论坛同源上传(无跨域,Via 可用),失败再降级到 img.binmt.cc 图床 // 图片大小上限(字节)。0 表示不限制。论坛附件一般建议 ≤ 2MB。 var MT_IMG_MAX_SIZE = 0; // 对图片做归一化:webp 等论坛 swfupload 不支持的格式,用 Canvas 转成 png 再上传。 // 返回 Promise(可原样返回或用转换后的 File 替换)。 function mtImageNormalize(file){ return new Promise(function(resolve){ var ext = (file.name||'').split('.').pop().toLowerCase(); // 论坛 swfupload 图片白名单(Discuz 默认):jpg/jpeg/gif/png/bmp var okExt = {jpg:1, jpeg:1, gif:1, png:1, bmp:1}; if(okExt[ext]){ resolve(file); return; } // 支持格式:原样直传 // 不支持格式(webp/heic/avif 等):尝试用 Canvas 转 png var url = URL.createObjectURL(file); var img = new Image(); img.onload = function(){ try{ var c = document.createElement('canvas'); c.width = img.naturalWidth; c.height = img.naturalHeight; var ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0); URL.revokeObjectURL(url); c.toBlob(function(blob){ if(blob){ var newName = (file.name||'image').replace(/\.[^.]+$/,'') + '.png'; var f = new File([blob], newName, {type:'image/png'}); resolve(f); } else { resolve(file); } // 转失败:原样返回,让后续逻辑提示 }, 'image/png'); }catch(e){ URL.revokeObjectURL(url); resolve(file); } }; img.onerror = function(){ URL.revokeObjectURL(url); resolve(file); }; img.src = url; }); } function mtImageUpload(file,cb){ var done=false; function finish(ok,res){ if(done)return; done=true; cb(ok,res); } mtImageNormalize(file).then(function(f){ // 大小限制(默认关闭 MT_IMG_MAX_SIZE=0;如需开启设 >0 字节) if(MT_IMG_MAX_SIZE && f && f.size && f.size > MT_IMG_MAX_SIZE){ finish(false,'图片超过 ' + Math.round(MT_IMG_MAX_SIZE/1024/1024) + 'MB,请压缩后重试'); return; } mtImageUploadForum(f,function(ok,res){ if(ok){ finish(true,res); return; } // 论坛同源上传失败 -> 降级到 img.binmt.cc 图床 mtImageUploadBed(f,finish); }); }).catch(function(){ finish(false,'图片处理失败'); }); } // 路径一:论坛同源附件上传(Discuz misc.php?mod=swfupload),无跨域限制,Via 环境 100% 可用 function mtImageUploadForum(file,cb){ var done=false; function finish(ok,res){ if(done)return; done=true; cb(ok,res); } var credCache=null; // 从当前页面 DOM 提取 uid + hash(附件上传 token,内联在编辑器 uploadformdata 里) function extractUploadCred(){ if(credCache&&credCache.uid&&credCache.hash)return credCache; var html=document.documentElement.innerHTML; var uid=null,hash=null; var mu=html.match(/uploadformdata:\s*\{[^}]*uid:\s*["']?(\d+)["']?/i); var mh=html.match(/hash:\s*["']([0-9a-f]{32})["']/i); if(mu)uid=mu[1]; if(mh)hash=mh[1]; // 兜底:也尝试从独立字段 / 变量读取 if(!uid && typeof window.discuz_uid!=='undefined'&&window.discuz_uid)uid=window.discuz_uid; if(!hash){ var m2=html.match(/uploadformdata\s*[:=]\s*\{[^}]*hash\s*[:=]\s*["']([^"']+)["']/i); if(m2)hash=m2[1]; } credCache={uid:uid,hash:hash}; return credCache; } var cred=extractUploadCred(); if(!cred.uid||!cred.hash){ finish(false,'不在回帖/发帖页面,无法使用论坛图床'); return; } var fd=new FormData(); fd.append('uid',cred.uid); fd.append('hash',cred.hash); fd.append('Filedata',file,file.name||'image.png'); var url='misc.php?mod=swfupload&operation=upload&type=image&inajax=yes&infloat=yes&simple=2'; fetch(url,{method:'POST',credentials:'include',body:fd}) .then(function(r){ return r.text(); }) .then(function(txt){ var raw=String(txt); var a=raw.split('|'); if(a[0]==='DISCUZUPLOAD' && a[2]==='0'){ var relPath=a[5]; if(relPath){ finish(true,(location.origin||'https://bbs.binmt.cc').replace(/\/$/,'')+'/data/attachment/forum/'+String(relPath).replace(/^\/+/,'')); } else{ finish(false,'上传成功但未获取到图片路径'); } } else { var code=a[2]; var STATUSMSG={'1':'不支持该扩展名','2':'服务器限制无法上传那么大的附件','3':'用户组限制无法上传那么大的附件','5':'文件类型限制无法上传该格式','6':'今日已无法上传更多文件','7':'请选择图片文件','8':'附件文件无法保存','9':'没有合法的文件被上传','10':'非法操作','11':'今日已无法上传更大的附件','-1':'内部服务器错误'}; var reason=STATUSMSG[code]||('错误码 '+code); finish(false,'论坛不支持该图片:'+reason); } }) .catch(function(){ finish(false,'论坛图床上传请求失败'); }); } // 路径二:降级 - 原 img.binmt.cc 图床两步上传(GET 首页取 csrf-token + cookie 会话 -> POST /upload) function mtImageUploadBed(file,cb){ var BASE='https://img.binmt.cc'; var useGM=(typeof GM_xmlhttpRequest==='function'); function failWhy(){ return useGM ? '图床上传失败(请检查脚本跨域授权 @connect)' : '图床上传失败(当前环境缺少 GM_xmlhttpRequest,跨域受限,请尝试手动输入链接)'; } // 从 set-cookie 响应头解析 cookie 键值,提取关键会话字段 // 兼容多种 responseHeaders 格式:字符串(换行分隔) / 对象{header:value} / 数组 function addCookie(jar, line){ var seg=String(line).replace(/^set-cookie\s*:\s*/i,'').split(';')[0]; var idx=seg.indexOf('='); if(idx>0){ var k=seg.slice(0,idx).trim(); var v=seg.slice(idx+1).trim(); if(k&&v) jar[k]=v; } } function parseCookies(headersStr){ var jar={}; if(!headersStr)return jar; if(typeof headersStr==='string'){ var lines=headersStr.split(/[\r\n]+/); lines.forEach(function(ln){ if(/^set-cookie\s*:/i.test(ln.trim())) addCookie(jar, ln); }); } else if(typeof headersStr==='object'){ // 对象形式:可能是 {header:value} 或数组 var arr=(Array.isArray(headersStr))?headersStr:[headersStr]; arr.forEach(function(o){ for(var k in o){ if(o.hasOwnProperty(k) && /set-cookie/i.test(String(k))) addCookie(jar, String(k)+': '+o[k]); } }); } return jar; } function cookieHeader(jar){ var parts=[]; for(var k in jar){ if(jar.hasOwnProperty(k)&&jar[k]) parts.push(k+'='+jar[k]); } return parts.join('; '); } function extractCsrf(txt){ var m=(txt||'').match(/csrf-token"\s*content="([^"]+)"/i)||(txt||'').match(/name="csrf-token"\s*content="([^"]+)"/i); return m?m[1]:''; } function doUpload(token,cookieJar){ var done=false; function finish(ok,res){ if(done)return; done=true; cb(ok,res); } if(useGM){ var fd=new FormData(); fd.append('file',file,file.name||'image.png'); var hdr={ 'Referer':BASE+'/', 'x-csrf-token':token }; var ck=cookieHeader(cookieJar); if(ck) hdr['Cookie']=ck; // 注意:不要手动设置 Content-Type,GM/浏览器会为 FormData 自动补 boundary GM_xmlhttpRequest({ method:'POST', url:BASE+'/upload', headers:hdr, data:fd, timeout:30000, onload:function(r){ try{ var txt=r.responseText||r.response||''; var j; if(typeof txt==='object') j=txt; else { try{ j=JSON.parse(txt); }catch(e){ j=null; } } if(j&&j.status&&j.data&&j.data.links&&j.data.links.url){ finish(true,j.data.links.url); } else{ finish(false,(j&&j.message)||('图床返回异常:'+String(txt).slice(0,60))); } }catch(e){ finish(false,'上传响应解析失败'); } }, onerror:function(){ finish(false,failWhy()); }, ontimeout:function(){ finish(false,'上传超时'); } }); return; } // 降级:页面 fetch(可能因 CORS 失败) var fd2=new FormData(); fd2.append('file',file,file.name||'image.png'); fetch(BASE+'/upload',{method:'POST',credentials:'include',headers:{'Referer':BASE+'/','x-csrf-token':token},body:fd2}) .then(function(r){ return r.json(); }) .then(function(j){ if(j&&j.status&&j.data&&j.data.links&&j.data.links.url)finish(true,j.data.links.url); else finish(false,(j&&j.message)||'上传失败'); }) .catch(function(){ finish(false,failWhy()); }); } function getToken(){ function onPage(txt,headersStr){ var t=extractCsrf(txt); var jar=headersStr?parseCookies(headersStr):{}; if(t){ doUpload(t,jar); } else { cb(false,'获取图床会话失败'); } } if(useGM){ // 关键:用 responseHeaders 抓 set-cookie,实现手动会话管理 GM_xmlhttpRequest({ method:'GET', url:BASE+'/', timeout:20000, responseHeaders:true, onload:function(r){ onPage(r.responseText, r.responseHeaders); }, onerror:function(){ cb(false,'无法访问图床'); } }); } else { fetch(BASE+'/',{credentials:'include'}).then(function(r){return r.text();}).then(function(t){onPage(t,'');}).catch(function(){ cb(false,'无法访问图床'); }); } } getToken(); } function ubbInjectStyle(){ if(document.getElementById('mt-ubb-style'))return; var st=document.createElement('style'); st.id='mt-ubb-style'; st.textContent='#mt-ubb-bar{display:flex;flex-wrap:wrap;gap:4px;padding:6px 10px;background:#f5f7fa;border:1px solid #e5e5e5;border-bottom:none;}'+ '#mt-ubb-bar .ub{display:inline-block;padding:3px 8px;border:1px solid #d0d0d0;border-radius:3px;background:#fff;color:#333;font-size:12px;line-height:16px;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;}'+ '#mt-ubb-bar .ub:active{background:#1e88e5;color:#fff;border-color:#1e88e5;}'; (document.head||document.documentElement).appendChild(st); } function ubbBuildBar(){ var ta=document.getElementById('needmessage'); if(!ta)return null; if(document.getElementById('mt-ubb-bar'))return document.getElementById('mt-ubb-bar'); ubbInjectStyle(); var bar=document.createElement('div'); bar.id='mt-ubb-bar'; var list=ubbList(); for(var i=0;i