Change Bilibili video miniscreen with your mouse wheel
// ==UserScript== // @name [Bilibili] 小窗尺寸缩放 // @name:en [Bilibili] MiniScreenResizer // @name:zh [Bilibili] 小窗尺寸缩放 // @namespace ckylin-script-bili-miniscreenresizer // @version 0.1 // @description 使用滚轮修改视频小窗口尺寸 // @description:en Change Bilibili video miniscreen with your mouse wheel // @description:zh 使用滚轮修改视频小窗口尺寸 // @author CKylinMC // @match https://www.bilibili.com/video/* // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getValue // @grant GM_setValue // @license GPLv3 License // ==/UserScript== (function() { const $ = q=>document.querySelector(q); const $$ = q=>[...document.querySelectorAll(q)]; const BVC = { mini: '.bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]', container: '.bpx-player-container', }; const CACHE = {}; const setWH = (e,w,h)=>(e.style.width=w+'px',e.style.height=h+'px',[w,h]); const parsePX = px=>parseFloat(px.replace('px','')); const getWH = e=>{const es = getComputedStyle(e);return [parsePX(es.width),parsePX(es.height)]}; const setTrans = (e,cancel)=>e.style.transition=cancel?'none':"width .3s ease, height .3s ease"; const wait = t => new Promise(r => setTimeout(r, t)); const setWHcss = (selector,w,h)=>css("RESIZERCSS",`${selector}{ width:${w}px!important;height:${h}px!important; }`); function css(id,content){ let el = $('style#'+id); if(!el){ el = document.createElement('style'); el.id = id; document.body.appendChild(el); } el.innerHTML = content; return el; } function parseFl (fl){ try{ const f = parseFloat(fl); if(!isNaN(f) && f>=0) return f; }catch(e){} return -1 } let menuIds = []; let menus = {}; const registerMenu = (text, callback) => menuIds.push(GM_registerMenuCommand(text, callback)); const clearMenu = () => { menuIds.forEach(id => GM_unregisterMenuCommand(id)); menuIds = []; }; async function playerReady(){ let i=50; while(--i>=0){ await wait(200); if(!('player' in unsafeWindow)) continue; if(!('isInitialized' in unsafeWindow.player)) continue; if(!unsafeWindow.player.isInitialized()) continue; return true; } return false; } async function waitForDom(q) { let i = 50; let dom; while (--i >= 0) { if (dom = $(q)) break; await wait(100); } return dom; } function applyMenus() { clearMenu(); for (let item in menus) { if(!menus.hasOwnProperty(item)) continue; let menu = menus[item]; registerMenu(menu.text, menu.callback); } } function setMenu(id,text,callback,noapply = false) { menus[id] = { text, callback }; if (!noapply) applyMenus(); } function resize(w,h){ const e = $(BVC.mini); setTrans(e); if(w&&h){ setWHcss(/*e*/BVC.mini,w,h); } return getWH(e); } (unsafeWindow||window).resizer = { $,$$,BVC,setWH,parsePX,getWH,setWHcss, resize } function prevent(e){ if(!CACHE.container) return; const el = CACHE.container; if(el.getAttribute('data-screen')!='mini'){ return; } e.preventDefault(); e.stopPropagation(); } function onMouseWheel(e){ if(!CACHE.container) return; const el = CACHE.container; if(el.getAttribute('data-screen')!='mini'){ return; } e.preventDefault(); e.stopPropagation(); console.log(e,e.wheelDeltaY); let [w,h] = getWH(CACHE.container); let delta = e.wheelDeltaY || e.deltaY; delta = 0.1*delta; w+=delta; h = w/16*9; setTrans(CACHE.container,true); setWHcss(/*CACHE.container*/BVC.mini,w,h); return false; } async function inject(){ await playerReady(); console.log('player ready'); await waitForDom(BVC.container); console.log('dom ready'); const el = $(BVC.container); if(!el) { throw new Error(); } console.log('element ready'); CACHE.container = el; el.addEventListener('onwheel',e=>prevent(e),false); el.addEventListener('mousewheel',e=>onMouseWheel(e),false); el.addEventListener('DOMMouseScroll',e=>onMouseWheel(e),false); } function init(){ [ { id:'240', text: "240x135", callback: ()=>resize(240,135) }, { id:'320', text: "320x180(默认)", callback: ()=>resize(320,180) }, { id:'480', text: "480x270", callback: ()=>resize(480,320) }, { id:'640', text: "640x360", callback: ()=>resize(640,360) }, { id:'custom', text: "自定义", callback: ()=>{ const curr = getWH($(BVC.mini)); const w = parseFl(prompt("宽度:(当前"+curr[0]+")")); if(w<0) return alert("输入不是有效大于0数字,已取消输入"); const h = parseFl(prompt("高度:(当前"+curr[1]+",根据输入的宽度("+w+")推荐高度:"+(Math.round(w/16*9))+")")); if(h<0) return alert("输入不是有效大于0数字,已取消输入"); setTimeout(()=>resize(w,h),200); } }, ].forEach(it=>setMenu(it.id,it.text,it.callback,true)); applyMenus(); inject().then(()=>console.log('[RESIZER] injected')).catch(e=>console.error('[RESIZER] cannot inject')); } init(); })();