增强页面音视频音量
当前为
// ==UserScript==
// @name 音量增强器
// @name:en-US Volume Booster
// @namespace System233
// @version 0.1
// @description 增强页面音视频音量
// @description:en-US Increase page audio and video volume
// @author System233
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant none
// @license GPL-3.0-only
// ==/UserScript==
// Copyright (c) 2022 System233
//
// This software is released under the GPL-3.0 License.
// https://opensource.org/licenses/GPL-3.0
(function () {
'use strict';
const setup = () => {
// /** @type {('Control'|'Shift'|'Alt')[]} */
const hotKeys = {
Control: true,
Shift: false,
Alt: true,
};
/** @type {(HTMLVideoElement|HTMLAudioElement)[]} */
const nodes = [...document.querySelectorAll('video,audio')];
nodes.forEach(node => {
const audioCtx = new AudioContext();
const gainNode = audioCtx.createGain();
const mediaSource = audioCtx.createMediaElementSource(node);
gainNode.connect(audioCtx.destination);
mediaSource.connect(gainNode);
let volume = 1;
Object.defineProperty(node, 'volumeBoost', {
get() {
return volume;
},
set(value) {
volume = Math.max(value,0);
gainNode.gain.setValueAtTime(volume, audioCtx.currentTime);
}
})
});
let index = 0;
let active = false;
let cleanupHandler = null;
const current = {
Control: false,
Shift: false,
Alt: false,
}
const length = nodes.length;
const cleanup = () => {
if (cleanupHandler != null) {
cleanupHandler();
cleanupHandler = null;
}
}
const keys = Object.keys(current);
const check = () => keys.findIndex(x => current[x] != hotKeys[x]) == -1;
const updateSelector = () => {
active = check();
cleanup();
if (active) {
focusOn(index);
updateText(true);
}else{
updateText(false);
}
}
const focusOn = (direction) => {
index = (index + length + direction) % length;
const node = nodes[index];
const { border, boxSizing } = node.style;
node.style.border = '.5em solid red';
node.style.boxSizing = 'border-box';
const rect = node.getBoundingClientRect();
if (rect.top + rect.height > window.innerHeight
|| rect.top < 0
|| rect.left < 0
|| rect.left + rect.width > window.innerWidth) {
node.scrollIntoView();
}
cleanupHandler = () => {
node.style.border = border;
node.style.boxSizing = boxSizing;
};
}
const updateText=(show)=>{
const META_KEY='VolumeBooster';
const node = nodes[index];
if(!show){
const el=Reflect.get(node,META_KEY);
if(el){
el.remove();
}
return;
}
/** @type {HTMLDivElement} */
const volumeBooster=Reflect.get(node,META_KEY)||document.createElement('div');
volumeBooster.style.color='red';
volumeBooster.style.position= 'absolute';
volumeBooster.style.right=0;
volumeBooster.style.background= '#ccc';
volumeBooster.style.padding='0.2em';
volumeBooster.style.zIndex=10000;
volumeBooster.innerHTML=`${Math.round(node.volumeBoost*100)}%`;
if(!volumeBooster.parentNode){
node.parentNode.append(volumeBooster);
Reflect.set(node,META_KEY,volumeBooster);
}
}
const boost = (step) => {
const node = nodes[index];
node.volumeBoost += step;
updateText(true);
}
const press = (key, press) => {
if (key in current) {
current[key] = press
}
updateSelector();
}
if(length){
document.addEventListener('keyup', e => press(e.key, false));
document.addEventListener('keydown', e => press(e.key, true));
document.addEventListener('keydown', e => {
if (active) {
switch (e.key) {
case 'ArrowUp': boost(.1); break;
case 'ArrowDown': boost(-.1); break;
case 'ArrowLeft': focusOn(-1); break;
case 'ArrowRight': focusOn(1); break;
}
}
})
}
}
window.addEventListener('load', setup);
})();