您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Soop 플레이어에 최대 16배 볼륨 증폭 슬라이더 추가
// ==UserScript== // @name Soop 추가 볼륨 슬라이더 // @namespace Soop 추가 볼륨 슬라이더 // @match *://*.play.sooplive.co.kr/* // @match *://vod.sooplive.co.kr/player/* // @version 0.2 // @description Soop 플레이어에 최대 16배 볼륨 증폭 슬라이더 추가 // @icon https://www.google.com/s2/favicons?sz=256&domain_url=play.afreecatv.com // @author mickey90427 <[email protected]> // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; const MAX_VOLUME = 16; let gainValue = getSavedVolume() || 1; const ORIGINAL_VOLUME = 1; let hideTimeout; function boostVolume(video, boost) { let audioContext = video.audioContext; let gainNode = video.gainNode; if (!audioContext) { audioContext = new (window.AudioContext || window.webkitAudioContext)(); let source = audioContext.createMediaElementSource(video); gainNode = audioContext.createGain(); source.connect(gainNode); gainNode.connect(audioContext.destination); video.audioContext = audioContext; video.gainNode = gainNode; video.addEventListener('play', () => audioContext.resume(), { once: true }); } gainNode.gain.value = boost ? gainValue : ORIGINAL_VOLUME; } function applyVolumeBoost() { document.querySelectorAll('video').forEach(video => boostVolume(video, true)); saveVolume(gainValue); } function addVolumeSlider() { const ctrl = document.querySelector('.ctrlBox .ctrl'); if (!ctrl) { setTimeout(addVolumeSlider, 500); return; } if (document.querySelector('#soopVolumeBoostSlider')) return; const container = document.createElement('div'); container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.marginLeft = '10px'; container.style.opacity = '0'; container.style.transition = 'opacity 0.3s'; const slider = document.createElement('input'); slider.id = 'soopVolumeBoostSlider'; slider.type = 'range'; slider.min = 1; slider.max = MAX_VOLUME; slider.value = gainValue; slider.step = 0.1; slider.style.width = '120px'; slider.style.cursor = 'pointer'; const label = document.createElement('span'); label.textContent = `🔊 ${gainValue.toFixed(1)}x`; label.style.color = '#fff'; label.style.fontSize = '12px'; label.style.marginLeft = '5px'; slider.oninput = () => { gainValue = parseFloat(slider.value); label.textContent = `🔊 ${gainValue.toFixed(1)}x`; applyVolumeBoost(); }; container.appendChild(slider); container.appendChild(label); // 볼륨 컨트롤 옆에 붙이기 const volumeBox = ctrl.querySelector('.volume'); if (volumeBox) { volumeBox.insertAdjacentElement('afterend', container); } else { ctrl.appendChild(container); } function showSlider() { container.style.opacity = '1'; resetHideTimeout(); } function hideSlider() { container.style.opacity = '0'; } function resetHideTimeout() { clearTimeout(hideTimeout); hideTimeout = setTimeout(hideSlider, 3000); } document.addEventListener('mousemove', showSlider); document.addEventListener('keydown', showSlider); } function saveVolume(value) { localStorage.setItem('soop_volume_boost', value); } function getSavedVolume() { const v = localStorage.getItem('soop_volume_boost'); return v ? parseFloat(v) : null; } function init() { function waitForVideo() { const videos = document.querySelectorAll('video'); if (videos.length > 0) { applyVolumeBoost(); addVolumeSlider(); } else { setTimeout(waitForVideo, 200); } } waitForVideo(); // 플레이어 DOM 변동 감지 const observer = new MutationObserver(() => waitForVideo()); observer.observe(document.body, { childList: true, subtree: true }); } init(); })();