Introducción
Existen ocasiones en las que navegamos por páginas web cuyo volumen de reproducción de medios es notablemente bajo. En lugar de ajustar el volumen del sistema o usar herramientas externas, podemos emplear una solución basada en scripts para usuarios avanzados que permite aumentar el volumen de elementos multimedia en la página.
Características clave
- Rango de ajuste de volumen: 0% a 666%
- Uso de Web Audio API para amplificación de audio
- Interfaz de usuario minimalista y funcional
- Compatibilidad con elementos dentro de iframes
- Soporte para múltiples plataformas de video
- Configuración personalizada por sitio web
- Panel de control en tiempo real
Limitaciones técnicas
Debido a las restricciones del estándar Web Audio API, un elemento multimedia solo puede ser procesado por un único contexto de audio. Esto significa que si otro script o la propia página ya está utilizando createMediaElementSource()>, nuestro script no podrá aplicarse.
Implementación técnica
El script utiliza únicamente JavaScript nativo sin dependencias externas, lo que garantiza compatibilidad con la mayoría de navegadores moderons (Chrome, Firefox, Edge).
Estructura principle del script
// ==UserScript==
// @name Amplificador de volumen web
// @namespace https://github.com/Stareven233
// @version 1.6.2
// @description Mejora el volumen de elementos multimedia en páginas web
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_notification
// @run-at document-end
// ==/UserScript==
(function () {
'use strict';
if (window._n_volumAmpInitialized) {
return;
}
window._n_volumAmpInitialized = true;
const MAX_AMP_FACTOR = 6.66;
const STEP_AMP = 0.01;
// Funciones de utilidad
function escapeHTML(str) {
return str.replace(/[&<>"']/g, m => ({
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
}[m]));
}
// Gestión de configuración
function loadConfig() {
return GM_getValue('ampConfig', { rules: [], active: true });
}
function saveConfig(config) {
GM_setValue('ampConfig', config);
}
function getSiteSettings() {
return GM_getValue('ampSettings', {});
}
function saveSettings(settings) {
GM_setValue('ampSettings', settings);
}
// Lógica de coincidencia de URLs
function matchUrl() {
const config = loadConfig();
if (!config.active || !config.rules?.length) {
return { matched: false };
}
const currentUrl = window.location.href;
for (const pattern of config.rules) {
try {
if (new RegExp(pattern).test(currentUrl)) {
return { matched: true, rule: pattern };
}
} catch (e) {
if (currentUrl.includes(pattern)) {
return { matched: true, rule: pattern };
}
}
}
return { matched: false };
}
// Panel de configuración
function openSettingsPanel() {
// Implementación del panel de configuración
}
// Registro de menú contextual
function registerMenu() {
// Implementación del menú de usuario
}
// Funcionalidad principal
let audioContext, gainControl;
function initializeAmplifier(videoElement, volumeLevel) {
try {
if (videoElement._ampBound) {
return true;
}
const AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
const source = audioContext.createMediaElementSource(videoElement);
gainControl = audioContext.createGain();
gainControl.gain.value = volumeLevel;
source.connect(gainControl).connect(audioContext.destination);
videoElement._ampBound = true;
// Resumir contexto de audio si está suspendido
const resumeAudio = () => {
if (audioContext.state === 'suspended') audioContext.resume();
};
window.addEventListener('mousedown', resumeAudio, { once: true });
window.addEventListener('keydown', resumeAudio, { once: true });
return true;
} catch (error) {
console.warn('Fallo al inicializar el amplificador:', error);
return false;
}
}
function createControlPanel(settings, rule) {
// Implementación del panel de control
}
// Lógica de inicio
const isMainFrame = window.self === window.top;
if (isMainFrame) registerMenu();
const { matched, rule } = matchUrl();
if (!matched && isMainFrame) return;
const siteSettings = getSiteSettings();
const currentSettings = (rule && siteSettings[rule]) || { selector: 'video', volume: 1.0 };
if (isMainFrame) {
createControlPanel(currentSettings, rule);
const statusTitle = document.getElementById('ampStatusTitle');
// Escuchar mensajes de iframes
window.addEventListener('message', (e) => {
if (e.data?.type === '_ampReady' && statusTitle) {
statusTitle.innerText = 'Amplificador de volumen';
}
});
// Buscar elementos de video
function findVideoElement() {
const video = document.querySelector(currentSettings.selector);
if (video) {
const success = initializeAmplifier(video, currentSettings.volume);
if (statusTitle) {
statusTitle.innerText = success ? 'Amplificador de volumen' : 'Fallo en inicialización - conflicto con otro script';
}
return success;
}
return false;
}
// Buscar video periódicamente
let attemptCount = 0;
const searchInterval = setInterval(() => {
if (findVideoElement() || attemptCount++ > 10) {
clearInterval(searchInterval);
}
}, 1000);
// Comunicación con iframes
setTimeout(() => {
for (const frame of document.querySelectorAll('iframe')) {
try {
frame.contentWindow.postMessage({
type: '_ampInit',
volume: currentSettings.volume,
selector: currentSettings.selector
}, '*');
} catch (_) { }
}
}, 2000);
} else {
// Lógica para elementos dentro de iframes
window.addEventListener('message', (e) => {
if (e.source !== window.parent) return;
if (e.data?.type === '_ampInit') {
const video = document.querySelector(e.data.selector || 'video');
if (video && initializeAmplifier(video, e.data.volume)) {
window.parent.postMessage({ type: '_ampReady' }, '*');
}
} else if (e.data?.type === '_ampVolume' && gainControl) {
gainControl.gain.value = e.data.volume;
}
});
}
})();
Función básica de amplificación
Para casos más simples, podemos usar esta versión compacta:
function amplifyMedia(mediaElement, factor) {
const context = new (window.AudioContext || window.webkitAudioContext);
const result = {
context: context,
source: context.createMediaElementSource(mediaElement),
gain: context.createGain(),
media: mediaElement,
amplify: function (factor) { this.gain.gain.value = factor },
getLevel: function () { return this.gain.gain.value }
};
result.source.connect(result.gain);
result.gain.connect(context.destination);
result.amplify(factor);
return result;
}
Uso: En la consola del navegador, tras seleccionar un elemento multimedia:
amplifyMedia(elem, 6)
Uso del script
- Instalar el script desde Greasy Fork
- Visitar una página con contenido multimedia
- Usar el menú contextual del script para:
- Añadir/quitar reglas para la página actual
- Gestionar reglas de coincidencia
- Usar el panel de control para:
- Ajustar el factor de amplificación en tiempo real
- Configurar selectores personalizados para elemnetos de video
- Guardar configuraciones específicas por sitio
Ejemplos de reglas de coincidencia
- URL específica:
https://ejemplo.tv/257254-3-4.html - Todas las páginas de Bilibili:
https?://www.bilibili.com/video/.* - Páginas de YouTube:
https?://www.youtube.com/watch?v=.* - Todas las páginas de un dominio:
https?://dominio.com/.*