Greasy Fork is available in English.
增強影片音量上限 , 最高增幅至10倍 , 未測試是否所有網域皆可使用 *://*/* , 目前只match特定網域
当前为
// ==UserScript==
// @name Video Volume Booster
// @version 0.0.24
// @author HentaiSaru
// @license MIT
// @icon https://cdn-icons-png.flaticon.com/512/8298/8298181.png
// @description 增強影片音量上限 , 最高增幅至10倍 , 未測試是否所有網域皆可使用 *://*/* , 目前只match特定網域
// @run-at document-start
// @match *://*.twitch.tv/*
// @match *://*.youtube.com/*
// @match *://*.bilibili.com/*
// @exclude *://video.eyny.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @namespace http://greasyfork.icu/users/989635
// ==/UserScript==
var Booster, modal, enabledDomains = GM_getValue("啟用網域", []), domain = window.location.hostname, Increase = 1.0;
(function() {
FindVideo();
MenuHotkey();
MonitorAjax();// 暴力解法(多少影響效能 , 個人沒感覺)
GM_registerMenuCommand("🔊 [開關] 自動增幅", function() {Useboost(enabledDomains, domain)});
GM_registerMenuCommand("🛠️ 設置增幅", function() {IncrementalSetting()});
GM_registerMenuCommand("📜 菜單熱鍵", function() {
alert("可使用熱鍵方式呼叫設置菜單!!\n\n快捷組合 : (Alt + B)");
});
})();
/* 監聽 Ajex 變化(fetch的不支援) */
async function MonitorAjax() {
let Video, VideoCache;
const originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
this.addEventListener("readystatechange", function () {
Video = document.querySelector("video");
if (this.readyState === 4 && Video) {
if (!Video.hasAttribute("data-audio-context") && Video !== VideoCache) {
FindVideo();
VideoCache = Video;
}
}
});
return originalXHROpen.apply(this, arguments);
}
}
/* 搜索 Video 元素 */
async function FindVideo() {
let interval, timeout=0;
interval = setInterval(function() {
const videoElement = document.querySelector("video");
if (videoElement) {
if (enabledDomains.includes(domain)) { // 沒開啟自動增幅的網頁也可以嘗試使用
let inc = GM_getValue(domain, []);
if (inc.length !== 0) {
Increase = inc;
}
}
try {
Booster = booster(videoElement, Increase);
} catch (error) {console.log(error)}
clearInterval(interval);
} else {
timeout++;
if (timeout === 3) {
clearInterval(interval);
}
}
}, 300);
}
/* 註冊快捷鍵(開啟菜單) */
async function MenuHotkey() {
document.addEventListener("keydown", function(event) {
if (event.altKey && event.key === "b") {
IncrementalSetting();
}
});
}
/* 音量增量 */
function booster(video, increase) {
const audioContext = new (window.AudioContext || window.webkitAudioContext);
// 音頻來源
const source = audioContext.createMediaElementSource(video);
// 增益節點
const gainNode = audioContext.createGain();
// 動態壓縮節點
const compressorNode = audioContext.createDynamicsCompressor();
// 將預設音量調整至 100% (有可能被其他腳本調整)
video.volume = 1;
// 設置增量
gainNode.gain.value = increase * increase;
// 設置動態壓縮器的參數(通用性測試!!)
compressorNode.ratio.value = 9; // 壓縮率
compressorNode.knee.value = 6; // 壓縮過度反應時間(越小越快)
compressorNode.threshold.value = -9; // 壓縮閾值
compressorNode.attack.value = 0.003; // 開始壓縮的速度
compressorNode.release.value = 0.6; // 釋放壓縮的速度
// 進行節點連結
source.connect(gainNode);
gainNode.connect(compressorNode);
compressorNode.connect(audioContext.destination);
video.setAttribute("data-audio-context", true);
return {
// 設置音量
setVolume: function(increase) {
gainNode.gain.value = increase * increase;
Increase = increase;
}
}
}
/* 使用自動增幅 */
function Useboost(enabledDomains, domain) {
if (enabledDomains.includes(domain)) {
// 從已啟用列表中移除當前網域
enabledDomains = enabledDomains.filter(function(value) {
return value !== domain;
});
alert("❌ 禁用自動增幅");
} else {
// 添加當前網域到已啟用列表
enabledDomains.push(domain);
alert("✅ 啟用自動增幅");
}
GM_setValue("啟用網域", enabledDomains);
location.reload();
}
GM_addStyle(`
.YT-modal-background {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
display: flex;
position: fixed;
overflow: auto;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.1);
}
.YT-modal-button {
top: 0;
margin: 3% 2%;
color: #d877ff;
font-size: 16px;
font-weight: bold;
border-radius: 3px;
background-color: #ffebfa;
border: 1px solid rgb(124, 183, 252);
}
.YT-modal-button:hover,
.YT-modal-button:focus {
color: #fc0e85;
cursor: pointer;
text-decoration: none;
}
.YT-modal-content {
width: 400px;
padding: 5px;
overflow: auto;
background-color: #cff4ff;
border-radius: 10px;
text-align: center;
border: 2px ridge #82c4e2;
border-collapse: collapse;
margin: 2% auto 8px auto;
}
.multiplier {
font-size:25px;
color:rgb(253, 1, 85);
margin: 10px;
font-weight:bold;
}
.slider {
width: 350px;
}
.hidden {
display: none;
}
`);
/* 設定模態 */
function IncrementalSetting() {
if (modal) {
modal.remove();
modal = null;
}
modal = document.createElement('div');
modal.innerHTML = `
<div class="YT-modal-content">
<h2 style="color: #3754f8;">音量增量</h2>
<div style="margin:1rem auto 1rem auto;">
<div class="multiplier">
<span><img src="https://cdn-icons-png.flaticon.com/512/8298/8298181.png" width="5%">增量倍數 </span><span id="currentValue">${Increase}</span><span> 倍</span>
</div>
<input type="range" class="slider" min="0" max="10.0" value="${Increase}" step="0.1"><br>
</div>
<div style="text-align: right;">
<button class="YT-modal-button" id="save">保存設置</button>
<button class="YT-modal-button" id="close">退出選單</button>
</div>
</div>
`
modal.classList.add('YT-modal-background');
document.body.appendChild(modal);
modal.classList.remove('hidden');
// 監聽設定拉條
modal.addEventListener("input", function(event) {
if (event.target.classList.contains("slider")) {
let currentValueElement = document.getElementById("currentValue");
let currentValue = event.target.value;
currentValueElement.textContent = currentValue;
Booster.setVolume(currentValue);
}
});
// 監聽保存按鈕
let saveButton = modal.querySelector("#save");
saveButton.addEventListener("click", () => {
if (enabledDomains.includes(domain)) {
let rangeValue = parseFloat(modal.querySelector(".slider").value);
GM_setValue(domain, rangeValue);
modal.classList.add("hidden");
} else {
alert("需啟用自動增幅才可保存");
}
});
// 監聽關閉按鈕點擊
let CloseButton = modal.querySelector("#close");
CloseButton.addEventListener("click", () => {
modal.classList.add("hidden");
});
}