// ==UserScript== // @name 아프리카 추가 볼륨 // @namespace 아프리카 추가 볼륨 // @match *://*.afreecatv.com/* // @version 0.2 // @description 아프리카 추가 증폭 볼륨을 구현합니다. // @icon https://www.google.com/s2/favicons?sz=256&domain_url=play.afreecatv.com // @author mickey90427 // @grant none // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 최대 볼륨 증폭 비율 const maxVolume = 16; const cookieName = 'afreecatv_volume'; let gainValue = getSavedVolume() || 1; // 쿠키에서 저장된 볼륨 값 불러오기, 기본값 1 // 쿠키에서 볼륨 값 불러오기 function getSavedVolume() { const cookieValue = document.cookie.split('; ').find(row => row.startsWith(`${cookieName}=`)); return cookieValue ? parseFloat(cookieValue.split('=')[1]) : null; } // 쿠키에 볼륨 값 저장 function saveVolume(value) { document.cookie = `${cookieName}=${value}; path=/; max-age=31536000`; // 1년 동안 저장 } // 볼륨 증폭 기능 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 : 1; } // 슬라이더 UI 생성 const volumeControl = document.createElement('div'); volumeControl.id = 'volumeControl'; volumeControl.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; volumeControl.style.padding = '10px'; volumeControl.style.borderRadius = '5px'; volumeControl.style.zIndex = '10000'; volumeControl.style.color = '#fff'; volumeControl.style.display = 'none'; // 처음에는 숨김 volumeControl.style.alignItems = 'center'; const volumeSlider = document.createElement('input'); volumeSlider.type = 'range'; volumeSlider.min = '1'; volumeSlider.max = maxVolume; volumeSlider.value = gainValue; volumeSlider.style.width = '150px'; volumeSlider.style.marginRight = '10px'; const percentageLabel = document.createElement('span'); percentageLabel.textContent = `${((gainValue - 1) / (maxVolume - 1) * 100).toFixed(2)}%`; percentageLabel.style.color = '#fff'; volumeControl.appendChild(volumeSlider); volumeControl.appendChild(percentageLabel); // 볼륨 변경 및 표시 업데이트 function setVolume(volume) { const videoElement = document.querySelector('video'); if (videoElement) { gainValue = volume; boostVolume(videoElement, true); percentageLabel.textContent = `${((gainValue - 1) / (maxVolume - 1) * 100).toFixed(2)}%`; saveVolume(gainValue); // 볼륨 값을 쿠키에 저장 } } // 슬라이더로 볼륨 설정 volumeSlider.addEventListener('input', function() { const volume = parseFloat(this.value); setVolume(volume); }); // 초기화 및 비디오 로드 감지 function updateVolumeSlider() { const videoElement = document.querySelector('video'); if (videoElement) { volumeSlider.value = gainValue; percentageLabel.textContent = `${((gainValue - 1) / (maxVolume - 1) * 100).toFixed(2)}%`; boostVolume(videoElement, true); } } // `ctrl` 요소에 볼륨 컨트롤 추가 function addVolumeControl() { const player = document.querySelector('#afreecatv_player'); const ctrl = document.querySelector('.ctrl'); if (player && ctrl) { // 기존 컨트롤이 있는지 확인하고 추가 if (!ctrl.querySelector('#volumeControl')) { ctrl.appendChild(volumeControl); player.addEventListener('mouseover', () => { volumeControl.style.display = 'flex'; }); player.addEventListener('mouseout', () => { volumeControl.style.display = 'none'; }); } } } // 초기 볼륨 업데이트 updateVolumeSlider(); addVolumeControl(); // MutationObserver로 비디오 요소 변경 감지 및 `ctrl` 요소 업데이트 const observer = new MutationObserver(() => { updateVolumeSlider(); addVolumeControl(); }); observer.observe(document.body, { childList: true, subtree: true }); })();