您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds Up/Down arrow key volume control with boost capability (>100%) to HTML5 videos using Web Audio API and displays a tip. Based on HTML5视频播放工具.
// ==UserScript== // @name HTML5 音量增强器 // @match *://*/* // @grant none // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @version 1.0 // @author AI // @license MIT // @description Adds Up/Down arrow key volume control with boost capability (>100%) to HTML5 videos using Web Audio API and displays a tip. Based on HTML5视频播放工具. // @namespace https://gf.qytechs.cn/users/1186846 // ==/UserScript== (function() { 'use strict'; // --- Configuration --- const VOLUME_STEP = 0.5; // How much to change gain per key press (original script used 0.5 for gain) const MAX_GAIN = 6; // Maximum volume gain (5 = 500%) const VIDEO_SELECTOR = 'video'; // How to find the video element. 'video' finds the first one. Adjust if needed. // --- Globals --- let v = null; // The currently controlled video element let $msg = null; // Tip message element (jQuery object) const by = document.body; // Reference to the body element // --- Tip Display Function (Requires jQuery) --- // Creates and shows a message centered on the video element const tip = (msg, videoEl = v) => { if (!videoEl || !msg) { // Don't show tip if no video or message if ($msg) $msg.css('opacity', 0); return; } // Initialize the message element if it doesn't exist if (!$msg) { $msg = $('<div/>').css({ 'position': 'fixed', // Use fixed positioning 'z-index': 2147483647, // Max z-index to be on top 'background': 'rgba(0,0,0,0.8)', 'color': '#FFF', 'font-size': '24px', 'font-weight': 'bold', 'padding': '12px 24px', 'border-radius': '8px', 'box-shadow': '0 4px 12px rgba(0,0,0,0.25)', 'pointer-events': 'none', // Don't intercept mouse events 'opacity': 0, // Start invisible 'transform': 'translate(-50%, -50%)', // Center align trick 'transition': 'opacity 0.3s', // Smooth fade 'white-space': 'nowrap' // Prevent line breaks }).appendTo(by); // Add to the body } // Calculate video center position const rect = videoEl.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; // Update message text and position, make visible $msg.text(msg) .css({ 'left': centerX + 'px', 'top': centerY + 'px', 'opacity': 1 }); // Set timer to fade out the message clearTimeout($msg.timer); // Clear previous timer $msg.timer = setTimeout(() => { if ($msg) $msg.css('opacity', 0); }, 2000); // Fade out after 2 seconds }; // --- Volume Adjustment Function (Uses Web Audio API for boosting) --- const adjustVolume = (n) => { // Attempt to find the video element if not already set or if it became invalid if (!v || !document.contains(v)) { v = document.querySelector(VIDEO_SELECTOR); } if (!v) { // console.log("AdjustVolume: No video element found."); return; // Exit if no video found } // Initialize AudioContext and GainNode if they don't exist on the video element if (!v.audioGainNode) { try { // Create AudioContext const audioContext = new (window.AudioContext || window.webkitAudioContext)(); // Create a source node from the video element const source = audioContext.createMediaElementSource(v); // Create a gain node (volume control) const gainNode = audioContext.createGain(); // Connect the source to the gain node source.connect(gainNode); // Connect the gain node to the audio output (speakers) gainNode.connect(audioContext.destination); // Store the gain node on the video element for later access v.audioGainNode = gainNode; // Set the video's native volume to 1 (max) so gainNode controls the actual volume v.volume = 1; console.log("AudioContext and GainNode initialized for video."); } catch (e) { // If Web Audio API fails (e.g., protected content, browser limitations) console.error('Failed to initialize AudioContext/GainNode:', e); // Fallback to standard HTML5 volume control (max 100%) const currentVolume = v.volume || 0; // Use smaller steps (0.1) for standard volume control as 0.5 is too coarse const volumeChange = n > 0 ? 0.1 : -0.1; const newVolume = Math.min(Math.max(currentVolume + volumeChange, 0), 1); v.volume = +newVolume.toFixed(2); tip(`Volume: ${Math.round(v.volume * 100)}%`); // Show standard volume percentage return; // Stop here after fallback } } // If AudioContext/GainNode exists, adjust the gain let currentGain = v.audioGainNode.gain.value; currentGain += n; // Apply the change (+/- VOLUME_STEP) // Clamp the gain between 0 and the configured MAX_GAIN currentGain = Math.max(0, Math.min(currentGain, MAX_GAIN)); // Apply the new gain value v.audioGainNode.gain.value = +currentGain.toFixed(2); // Display the gain multiplier (e.g., "🔊 1.5x") tip(`🔊 ${currentGain.toFixed(1)}x`); }; // --- Keydown Event Handler --- function handleVolumeKeys(e) { const t = e.target; // Ignore keys if typing in inputs, focused on editable content, or if modifier keys are pressed if (e.ctrlKey || e.metaKey || e.altKey || t.isContentEditable || /INPUT|TEXTAREA|SELECT/i.test(t.nodeName)) { return; } let action = null; // Check for Up Arrow (increase volume) or Down Arrow (decrease volume) switch (e.keyCode) { case 38: // Up Arrow action = () => adjustVolume(VOLUME_STEP); break; case 40: // Down Arrow action = () => adjustVolume(-VOLUME_STEP); break; } if (action) { // Try to find the video element (most relevant one might be the focused one or the first one) const currentVideo = document.querySelector(VIDEO_SELECTOR); // Re-check for video if (currentVideo) { v = currentVideo; // Update the global 'v' if found // Heuristic: Apply if the body or the video itself has focus, to avoid hijacking keys unintentionally. const activeElement = document.activeElement; const isVideoRelated = v.contains(activeElement) || v === activeElement; const isBodyFocused = activeElement === by || activeElement === null; if (isVideoRelated || isBodyFocused) { e.preventDefault(); // Prevent default arrow key behavior (scrolling) e.stopPropagation(); // Stop event bubbling action(); // Perform the volume adjustment } } } } // --- Initialization --- function init() { console.log("Initializing Standalone Volume Booster..."); // Find the initial video element v = document.querySelector(VIDEO_SELECTOR); if (v) { console.log("Initial video element found:", v); } else { console.log("No video element found on initial load. Will check during key events."); } // Add the keydown listener to the document body by.addEventListener('keydown', handleVolumeKeys); console.log("Volume key listener attached to body."); } // --- Run Initialization --- // Wait for jQuery to be ready (if using @require) and DOM to be loaded if (typeof $ === 'undefined') { console.error("Volume Booster: jQuery is required for the volume tip display."); // Fallback or error handling if jQuery isn't present } else { // Run init() slightly delayed after DOM is ready if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(init, 500); } else { window.addEventListener('DOMContentLoaded', () => setTimeout(init, 500)); } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址