// ==UserScript==
// @name B站小窗口视频功能显示
// @description 增强B站功能,B站小窗口视频的操作栏显示
// @version 0.0.5
// @author Grant Howard, Coulomb-G
// @copyright 2024, Grant Howard
// @license MIT
// @match *://*.bilibili.com/video/*
// @match *://*.bilibili.com/bangumi/play/*
// @exclude *://api.bilibili.com/*
// @exclude *://api.*.bilibili.com/*
// @exclude *://*.bilibili.com/api/*
// @exclude *://member.bilibili.com/studio/bs-editor/*
// @exclude *://t.bilibili.com/h5/dynamic/specification
// @exclude *://bbq.bilibili.com/*
// @exclude *://message.bilibili.com/pages/nav/header_sync
// @exclude *://s1.hdslb.com/bfs/seed/jinkela/short/cols/iframe.html
// @exclude *://open-live.bilibili.com/*
// @run-at document-start
// @grant unsafeWindow
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_info
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_addStyle
// @connect raw.githubusercontent.com
// @connect github.com
// @connect cdn.jsdelivr.net
// @connect cn.bing.com
// @connect www.bing.com
// @connect translate.google.cn
// @connect translate.google.com
// @connect localhost
// @connect *
// @icon https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/logo-small.png
// @icon64 https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/logo.png
// @namespace https://greasyfork.org/users/734541
// ==/UserScript==
(() => {
GM_addStyle(`
#commenBoxBody{
position: fixed;
z-index: 100;
bottom: 5px;
left: 0;
width:300px;
height: 32px;
background: transparent;
padding: 0;
}
`);
const console = (() => {
const _console = window.console;
return {
log: (...args) => {
_console.log(
`%c ZAIZAI `,
'padding: 2px 1px; border-radius: 3px; color: #fff; background: #42c02e; font-weight: bold;',
...args,
);
},
};
})();
function waitTime(callback, options = { time: 500, isSetup: false }) {
let timeout = null;
return new Promise((resolve) => {
if (options.isSetup) {
let res = callback();
if (res) resolve(res);
}
timeout = setInterval(() => {
let res = callback();
if (res) {
clearInterval(timeout);
resolve(res);
}
}, options.time);
});
}
/**
* 创建一个节流函数
* @param {Function} func 需要节流的函数
* @param {number} wait 函数执行的最小时间间隔
* @param {boolean} [options={leading=true, trailing=true}] 配置对象
* @returns {Function} 节流后的函数
*/
function throttle(func, wait, options = {}) {
let timeout = null;
let context, args;
let previousNow = 0;
const { leading = true, trailing = true } = options;
function wrapper() {
// Save the context and arguments
context = this;
args = arguments;
const previous = previousNow;
const remaining = wait - (Date.now() - previous);
const now = Date.now();
if (remaining <= 0 || remaining > wait) {
// 如果当前调用距离上次调用超过了wait时间,则立即执行
clearTimeout(timeout);
timeout = null;
func.apply(context, args);
previousNow = now;
} else if (!timeout && trailing) {
// 如果设置了trailing,则在wait时间结束时执行
timeout = setTimeout(() => {
func.apply(context, args);
previousNow = now;
}, remaining);
}
if (leading && !timeout) {
// 如果设置了leading,则在第一次调用时立即执行
func.apply(context, args);
previousNow = now;
}
}
return wrapper;
}
console.log('B站小窗口视频功能显示');
const state = {
is: false,
};
const onMouseover = async () => {
if (state.is) {
return;
}
state.is = true;
const els = await waitTime(
() => {
const bpxplayercontrolmask = document.querySelector('.bpx-player-control-mask');
const bpxplayercontrolentity = document.querySelector('.bpx-player-control-entity');
const bpxplayercontrolbottom = document.querySelector('.bpx-player-control-bottom');
if (bpxplayercontrolmask && bpxplayercontrolentity && bpxplayercontrolbottom) {
return [bpxplayercontrolmask, bpxplayercontrolentity, bpxplayercontrolbottom];
}
},
{
time: 0,
},
);
els[0].style.opacity = 1;
els[0].style.display = 'block';
els[1].style.opacity = 1;
els[1].style.display = 'block';
els[2].style.opacity = 1;
els[2].style.display = 'flex';
console.log('onMouseover 显示');
console.log(els);
};
const onMouseout = async (e) => {
if (!state.is && e.tae) {
return;
}
state.is = false;
const els = await waitTime(
() => {
const bpxplayercontrolmask = document.querySelector('.bpx-player-control-mask');
const bpxplayercontrolentity = document.querySelector('.bpx-player-control-entity');
const bpxplayercontrolbottom = document.querySelector('.bpx-player-control-bottom');
if (bpxplayercontrolmask && bpxplayercontrolentity && bpxplayercontrolbottom) {
return [bpxplayercontrolmask, bpxplayercontrolentity, bpxplayercontrolbottom];
}
},
{
time: 0,
},
);
els[0].style.opacity = 0;
els[0].style.display = 'none';
els[1].style.opacity = 0;
els[1].style.display = 'none';
els[2].style.opacity = 0;
els[2].style.display = 'none';
console.log('onMouseout 隐藏');
console.log(els);
};
const addCommentBoxButton = async () => {
if (document.querySelector('#zaizai_commentBox')) {
console.log('已经添加了评论框按钮');
return;
}
const elBut = await waitTime(() => {
let button = document.querySelector('.bpx-player-ctrl-btn.bpx-player-ctrl-playbackrate');
let commentBox = document.querySelector('.bpx-player-video-inputbar');
if (button && commentBox) {
button = button.cloneNode(true);
button.children[0].textContent = '框';
button.id = 'zaizai_commentBox';
commentBox = commentBox.cloneNode(true);
commentBox.querySelector('.bpx-player-video-btn-dm').remove();
commentBox.querySelector('.bpx-player-video-preview-emoji-wrap').remove();
commentBox.querySelector('.bpx-player-dm-hint').remove();
// 隐藏按钮
const hiheEl = document.createElement('div');
hiheEl.classList.add('bpx-player-video-btn-dm');
hiheEl.style.color = '#000';
hiheEl.style.lineHeight = '25px';
hiheEl.textContent = '隐藏';
commentBox.prepend(hiheEl);
// 容器
const commenBoxBody = document.createElement('div');
commenBoxBody.id = 'commenBoxBody';
commenBoxBody.classList.add('bpx-player-sending-bar');
commenBoxBody.style.display = 'none';
commenBoxBody.style.padding = '0';
commenBoxBody.appendChild(commentBox);
const sendBut = commentBox.querySelector('.bpx-player-dm-btn-send');
const inputEl = commentBox.querySelector('.bpx-player-dm-input');
return [button, commenBoxBody, hiheEl, sendBut, inputEl];
}
});
elBut[0].addEventListener('click', () => {
let display = elBut[1].style.display;
elBut[1].removeAttribute('tsbrowser_force_hidden');
if (display === 'none') {
elBut[1].style.display = 'block';
elBut[1].style.zIndex = 9999;
elBut[1].style.left = (document.body.getBoundingClientRect().width - 300) / 2 + 'px';
} else {
elBut[1].style.display = 'none';
}
});
elBut[2].addEventListener('click', () => {
elBut[1].style.display = 'none';
});
elBut[3].addEventListener('click', () => {
const value = elBut[4].value;
const playerInput = document.querySelector('#bilibili-player .bpx-player-dm-input');
playerInput.focus();
document.execCommand('insertText', false, value);
document.querySelector('#bilibili-player .bpx-player-dm-btn-send').click();
elBut[4].value = '';
elBut[3].classList.add('bui-disabled');
elBut[3].children[0].textContent = '0';
let timeout = null;
let count = 1;
timeout = setInterval(() => {
count++;
if (count >= 6) {
elBut[3].classList.remove('bui-disabled');
elBut[3].children[0].textContent = '发送';
clearTimeout(timeout);
} else {
elBut[3].children[0].textContent = count;
}
}, 1000);
});
document.body.appendChild(elBut[1]);
document.querySelector('.bpx-player-control-bottom-right').prepend(elBut[0]);
};
window.onload = () => {
window.addEventListener('resize', async () => {
const { innerWidth, innerHeight } = window;
if (innerWidth <= 565 && innerHeight <= 320) {
window.addEventListener('mouseover', onMouseover);
window.addEventListener('mouseout', onMouseout);
addCommentBoxButton();
} else if (innerWidth > 565 && innerHeight > 320) {
window.removeEventListener('mouseover', onMouseover);
window.removeEventListener('mouseout', onMouseout);
state.is = false;
/**
* 放大后清空 style 不然b站原本的css不会生效
*/
const els = await waitTime(
() => {
const bpxplayercontrolmask = document.querySelector('.bpx-player-control-mask');
const bpxplayercontrolentity = document.querySelector('.bpx-player-control-entity');
const bpxplayercontrolbottom = document.querySelector('.bpx-player-control-bottom');
if (bpxplayercontrolmask && bpxplayercontrolentity && bpxplayercontrolbottom) {
return [bpxplayercontrolmask, bpxplayercontrolentity, bpxplayercontrolbottom];
}
},
{
time: 0,
},
);
els.forEach((item) => {
item.style.cssText = '';
});
}
if (innerWidth <= 520) {
document.querySelector('.bpx-player-ctrl-time').style.display = 'none';
document.querySelector('.bpx-player-ctrl-quality').style.display = 'none';
} else {
document.querySelector('.bpx-player-ctrl-time').style.display = 'block';
document.querySelector('.bpx-player-ctrl-quality').style.display = 'block';
}
});
};
})();