您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Amplifie le volume Twitch en combinant volume natif et gain WebAudio, avec UI native améliorée.
// ==UserScript== // @name Amplificateur de volume Twitch // @namespace https://linktr.ee/yakenofficielle // @version 5.4 // @description Amplifie le volume Twitch en combinant volume natif et gain WebAudio, avec UI native améliorée. // @author NatioLaurin // @match https://www.twitch.tv/* // @grant none // @license Yaken // ==/UserScript== (function () { 'use strict'; let audioCtx = null; let gainNode = null; let sourceNode = null; let video = null; let lastVideoSrc = null; let amplificationGain = 1; // amplification multipliée au volume natif let nativeVolume = 1; // volume natif (slider Twitch) // Slider amplification custom (petit et discret) let ampSliderContainer = null; let ampSlider = null; let dragHandle = null; let isDragging = false; let offset = { x: 0, y: 0 }; function createAmplificationSlider() { if (ampSliderContainer) return; ampSliderContainer = document.createElement("div"); Object.assign(ampSliderContainer.style, { position: "fixed", top: "20px", right: "20px", width: "140px", backgroundColor: "rgba(24, 24, 27, 0.90)", borderRadius: "8px", boxShadow: "0 4px 12px rgba(0,0,0,0.7)", padding: "8px", display: "flex", flexDirection: "column", alignItems: "center", zIndex: "99999", userSelect: "none", color: "white", fontFamily: "Arial, sans-serif", fontSize: "13px", }); const label = document.createElement("div"); label.textContent = "🔊Amplification"; label.style.marginBottom = "6px"; label.style.fontWeight = "600"; label.style.paddingRight = "18px"; ampSliderContainer.appendChild(label); ampSlider = document.createElement("input"); ampSlider.type = "range"; ampSlider.min = "1"; ampSlider.max = "5"; ampSlider.step = "0.1"; ampSlider.value = amplificationGain.toString(); Object.assign(ampSlider.style, { width: "100%", cursor: "pointer", accentColor: "#9147FF", }); ampSliderContainer.appendChild(ampSlider); dragHandle = document.createElement("div"); Object.assign(dragHandle.style, { width: "16px", height: "16px", backgroundColor: "#9147FF", borderRadius: "4px", cursor: "grab", position: "absolute", top: "8px", right: "8px", marginTop: "0", alignSelf: "auto", }); dragHandle.title = "Déplacer"; ampSliderContainer.appendChild(dragHandle); document.body.appendChild(ampSliderContainer); dragHandle.addEventListener("mousedown", e => { isDragging = true; const rect = ampSliderContainer.getBoundingClientRect(); offset.x = e.clientX - rect.left; offset.y = e.clientY - rect.top; e.preventDefault(); }); document.addEventListener("mousemove", e => { if (isDragging) { ampSliderContainer.style.left = `${e.clientX - offset.x}px`; ampSliderContainer.style.top = `${e.clientY - offset.y}px`; ampSliderContainer.style.right = "auto"; ampSliderContainer.style.bottom = "auto"; } }); document.addEventListener("mouseup", () => { isDragging = false; }); ampSlider.addEventListener("input", () => { amplificationGain = parseFloat(ampSlider.value); updateGain(); console.log(`[Booster] Amplification réglée sur ${amplificationGain}x`); }); } function updateGain() { if (gainNode) { let newGain = nativeVolume * amplificationGain; if (newGain > 10) newGain = 10; gainNode.gain.value = newGain; } } async function attachToVideo() { const candidate = document.querySelector('video'); if (!candidate || candidate.readyState < 1) return; if (candidate.src === lastVideoSrc && audioCtx) { if (audioCtx.state === 'suspended') { await audioCtx.resume(); console.log("[Booster] AudioContext repris"); } return; } if (audioCtx) { try { await audioCtx.close(); console.log("[Booster] AudioContext fermé"); } catch (e) { console.warn("[Booster] Erreur en fermant AudioContext", e); } audioCtx = null; gainNode = null; sourceNode = null; } try { video = candidate; lastVideoSrc = video.src; audioCtx = new (window.AudioContext || window.webkitAudioContext)(); sourceNode = audioCtx.createMediaElementSource(video); gainNode = audioCtx.createGain(); gainNode.gain.value = nativeVolume * amplificationGain; sourceNode.connect(gainNode).connect(audioCtx.destination); if (audioCtx.state === 'suspended') { await audioCtx.resume(); console.log("[Booster] AudioContext démarré"); } console.log("[Booster] Audio connecté à la vidéo Twitch."); watchNativeVolumeSlider(); } catch (err) { console.error("[Booster] Impossible de connecter l'audio :", err); } } function watchNativeVolumeSlider() { const nativeSlider = document.querySelector('input[data-test-selector="volume-slider"]'); if (!nativeSlider) return; nativeVolume = parseFloat(nativeSlider.value) || 1; nativeSlider.oninput = () => { nativeVolume = parseFloat(nativeSlider.value); updateGain(); console.log(`[Booster] Volume natif réglé sur ${nativeVolume}`); }; } setInterval(() => { createAmplificationSlider(); attachToVideo(); }, 1000); })();