您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Restore right/middle-click new tab function on manko.fun / solji.kim.
// ==UserScript== // @name Restore Right/Middle-Click New Tab Links for manko.fun / solji.kim // @namespace http://tampermonkey.net/ // @version 1.3.1 // @description Restore right/middle-click new tab function on manko.fun / solji.kim. // Note: This script works properly in Tampermonkey when Developer Mode is enabled. // // @author VanillaMilk // @license MIT // @match https://manko.fun/* // @match https://solji.kim/* // @run-at document-end // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (async function () { 'use strict' const ID_ATTR='data-id' const DEST_BASE='https://solji.kim/movie-info/' const KEY_OPEN_BLANK='mf_linkifier_open_blank' const KEY_SIDE_NAV='mf_linkifier_side_nav' const Rt = { en: { popular:"Popular","most popular":"Most Popular","top rated":"Top Rated",top_rated:"Top Rated",new:"New",subtitle:"Subtitle",random:"Random",category:"Category",actor:"Actor",genre:"Genre",country:"Country",usecase:"Download app",censored:"Censored",uncensored:"Uncensored",fc2:"FC2" }, zh: { popular:"热门作品","most popular":"热门作品","top rated":"最佳评分",top_rated:"最佳评分",new:"最新作品",subtitle:"字幕",random:"随机",category:"类别",actor:"演员",genre:"类型",country:"国家",usecase:"下载应用程序",censored:"马赛克",uncensored:"无马赛克",fc2:"FC2" }, tw: { popular:"受歡迎的","most popular":"受歡迎的","top rated":"最高評分",top_rated:"最高評分",new:"新的",subtitle:"字幕",random:"隨機的",category:"類別",actor:"演員",genre:"類型",country:"國家",usecase:"下載應用程式",censored:"審查",uncensored:"未經審查",fc2:"FC2" }, ja: { popular:"人気","most popular":"人気","top rated":"最高評価",top_rated:"最高評価",new:"新作",subtitle:"字幕",random:"ランダム",category:"カテゴリー",actor:"俳優",genre:"ジャンル",country:"国名",usecase:"アプリをダウンロード",censored:"修正",uncensored:"無修正",fc2:"FC2" }, ko: { popular:"인기작","most popular":"인기작","top rated":"최고평점",top_rated:"최고평점",new:"신작",subtitle:"자막",random:"랜덤",category:"카테고리",actor:"배우",genre:"장르",country:"국가",usecase:"앱 다운로드",censored:"유모",uncensored:"노모",fc2:"FC2" }, id: { popular:"Populer","most popular":"Populer","top rated":"Peringkat Teratas",top_rated:"Peringkat Teratas",new:"Baru",subtitle:"Subjudul",random:"Acak",category:"Kategori",actor:"Aktor",genre:"Genre",country:"Negara",usecase:"Unduh aplikasi",censored:"Disensor",uncensored:"Tanpa Sensor",fc2:"FC2" }, ms: { popular:"Popular","most popular":"Popular","top rated":"Tertinggi",top_rated:"Tertinggi",new:"baru",subtitle:"Sari kata",random:"rawak",category:"kategori",actor:"pelakon",genre:"Genre",country:"Negara",usecase:"Muat turun aplikasi",censored:"ditapis",uncensored:"Tidak ditapis",fc2:"FC2" }, th: { popular:"เป็นที่นิยม","most popular":"เป็นที่นิยม","top rated":"อันดับสูงสุด",top_rated:"อันดับสูงสุด",new:"ใหม่",subtitle:"คำบรรยาย",random:"สุ่ม",category:"หมวดหมู่",actor:"นักแสดงชาย",genre:"ประเภท",country:"ประเทศ",usecase:"ดาวน์โหลดแอป",censored:"เซ็นเซอร์",uncensored:"ไม่เซ็นเซอร์",fc2:"เอฟซี2" }, vi: { popular:"Phổ biến","most popular":"Phổ biến","top rated":"Đánh giá cao nhất",top_rated:"Đánh giá cao nhất",new:"Mới",subtitle:"Phụ đề",random:"Ngẫu nhiên",category:"Loại",actor:"Diễn viên",genre:"Thể loại",country:"Quốc gia",usecase:"Tải ứng dụng",censored:"Bị kiểm duyệt",uncensored:"Không kiểm duyệt",fc2:"FC2" } } function englishParamForKey(key){ if(!key) return null if(key==='popular') return Rt.en['most popular'] || 'Most Popular' return Rt.en[key] || key } function cleanText(t){ return (t||'').replace(/[\p{Extended_Pictographic}\p{Emoji_Presentation}\uFE0F\u200D\u2600-\u27BF]/gu,'').trim() } function labelToKey(label){ const t = cleanText(label).toLowerCase() for(const map of Object.values(Rt)){ for(const [k,v] of Object.entries(map)){ if(String(v).toLowerCase()===t) return k } } if(t==='top rated') return 'top rated' if(t==='most popular') return 'most popular' return null } async function gv(k,d='0'){try{return String(await GM_getValue(k,d))==='1'}catch{return false}} async function sv(k,v){try{await GM_setValue(k,v?'1':'0')}catch{}} let useBlank=await gv(KEY_OPEN_BLANK,'0') let sideEnable=await gv(KEY_SIDE_NAV,'0') if(typeof GM_registerMenuCommand==='function'){ GM_registerMenuCommand((useBlank?'☑ ':'☐ ')+'Left-click opens in new tab',async()=>{useBlank=!useBlank;await sv(KEY_OPEN_BLANK,useBlank);location.reload()}) GM_registerMenuCommand((sideEnable?'☑ ':'☐ ')+'Side buttons: page ±1',async()=>{sideEnable=!sideEnable;await sv(KEY_SIDE_NAV,sideEnable);location.reload()}) } (function normalizePageForPagination() { try { const u = new URL(location.href); const path = u.pathname; const isEligible = /^\/(movie-list|cate-list|actor-list|home)/.test(path); const isExcluded = /^\/(genre|maker|usecase)/.test(path); if (isEligible && !isExcluded && !u.searchParams.has('page')) { u.searchParams.set('page', '1'); history.replaceState(null, '', u.toString()); } } catch {} })(); if (sideEnable) { let last = 0; const side = (e) => { if (e.button !== 3 && e.button !== 4) return; const u = new URL(location.href); const path = u.pathname; const isEligible = /^\/(movie-list|cate-list|actor-list)/.test(path); const isExcluded = /^\/(genre|maker|usecase)/.test(path); const hasQ = u.searchParams.has('page'); const hs = u.hash.startsWith('#') ? u.hash.slice(1) : u.hash; const sp = new URLSearchParams(hs); const hasH = sp.has('page'); if (isEligible && !isExcluded && !hasQ && !hasH) { u.searchParams.set('page','1'); e.stopImmediatePropagation?.(); e.stopPropagation?.(); e.preventDefault?.(); location.assign(u.toString()); return; } if (!hasQ && !hasH) return; const now = Date.now(); if (now - last < 120) return; last = now; const delta = (e.button === 3) ? -1 : 1; let p = hasQ ? parseInt(u.searchParams.get('page') || '1', 10) : parseInt(sp.get('page') || '1', 10); if (!Number.isFinite(p) || p < 1) p = 1; let n = p + delta; if (n < 1) n = 1; if (hasQ) { u.searchParams.set('page', String(n)); } else { sp.set('page', String(n)); u.hash = '#' + sp.toString(); } e.stopImmediatePropagation?.(); e.stopPropagation?.(); e.preventDefault?.(); location.assign(u.toString()); }; addEventListener('mouseup', side, true); addEventListener('pointerup', side, true); } const style=document.createElement('style') style.textContent=` .tm-wrap{position:relative!important;} .tm-ol{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;display:block!important;background:transparent!important;text-decoration:none!important;outline:none!important;pointer-events:auto!important;} ` document.documentElement.appendChild(style) function wrap(el, forceNew){ if(!forceNew){ const p=el.parentElement if(p){const cs=getComputedStyle(p);if(cs.position!=='static')return p} } const w=document.createElement('span');w.className='tm-wrap';w.style.position='relative' el.parentNode?.insertBefore(w,el);w.appendChild(el);return w } function setOverlay(el,href,forceNew){ const w=wrap(el,forceNew) let a=w.querySelector(':scope > a.tm-ol') if(!a){a=document.createElement('a');a.className='tm-ol';a.rel='noopener noreferrer';w.appendChild(a)} a.href=href a.target=useBlank?'_blank':'_self' return a } function linkifyCard(card){ if(!(card instanceof Element))return if(!card.hasAttribute(ID_ATTR))return if(card.__tm_done__)return const raw=card.getAttribute(ID_ATTR)||'' const id=raw.split('?')[0].trim() if(!id)return setOverlay(card,DEST_BASE+encodeURIComponent(id),true) card.__tm_done__=true } function scanCards(root){ root.querySelectorAll(`[${ID_ATTR}]`).forEach(linkifyCard) linkifyCard(root) } scanCards(document.body||document.documentElement) const moCards=new MutationObserver(muts=>{ for(const m of muts){ if(m.type==='childList')m.addedNodes.forEach(n=>n.nodeType===1&&scanCards(n)) else if(m.type==='attributes'&&m.attributeName===ID_ATTR)linkifyCard(m.target) } }) moCards.observe(document.documentElement,{childList:true,subtree:true,attributes:true,attributeFilter:[ID_ATTR]}) function hrefForTopLabel(txt){ const key = labelToKey(txt) if(!key) return null if(key==='category' || key==='actor') return null if(key==='genre') return '/genre' if(key==='country') return '/maker' if(key==='usecase') return '/usecase' const cat = englishParamForKey(key) || cleanText(txt) return `/movie-list?category=${encodeURIComponent(cat)}` } function linkifyTopNav(root){ root.querySelectorAll('nav button').forEach(btn=>{ if(btn.__tm_top__)return const txt=cleanText(btn.textContent||'');if(!txt)return const href=hrefForTopLabel(txt) if(!href) return setOverlay(btn,href,true) btn.__tm_top__=true }) } const CATEGORY_FIXED_KEYS=new Set(['censored','uncensored','popular','top rated','top_rated','fc2']) const ACTOR_FIXED_KEYS =new Set(['censored','uncensored']) function resolveDropdownMode(pop){ let n=pop.previousElementSibling||pop.parentElement?.previousElementSibling if(n){ const k = labelToKey(cleanText(n.textContent||'')) if(k==='actor') return 'actor' if(k==='category') return 'category' } return 'category' } function linkifyDropdown(pop){ const mode=resolveDropdownMode(pop) pop.querySelectorAll('button').forEach(btn=>{ if(btn.__tm_dd__)return const label=cleanText(btn.textContent||'');if(!label)return const key = labelToKey(label) let href if(mode==='actor'){ if(key && ACTOR_FIXED_KEYS.has(key)){ const cat = englishParamForKey(key) || key href = `/actor-list?category=${encodeURIComponent(cat)}&page=1` }else{ href = `/actor-list?category=${encodeURIComponent(label)}&page=1` } }else{ if(key && CATEGORY_FIXED_KEYS.has(key)){ const cat = englishParamForKey(key) || key href = `/cate-list?category=${encodeURIComponent(cat)}&page=1` }else{ href = `/cate-list?category=${encodeURIComponent(label)}&page=1` } } setOverlay(btn,href,true) btn.__tm_dd__=true }) } function fullScan(root){ linkifyTopNav(root) root.querySelectorAll('div.absolute').forEach(div=>{ if(div.querySelector('button'))linkifyDropdown(div) }) } fullScan(document.body||document.documentElement) const moMenus=new MutationObserver(muts=>{ for(const m of muts){ if(m.type==='childList'){ m.addedNodes.forEach(n=>{if(n.nodeType===1)fullScan(n)}) }else if(m.type==='attributes'&&(m.attributeName==='class'||m.attributeName==='style'||m.attributeName==='aria-expanded')){ if(m.target instanceof Element)fullScan(m.target) } } }) moMenus.observe(document.documentElement,{childList:true,subtree:true,attributes:true,attributeFilter:['class','style','aria-expanded']}) })()