아프리카 추가 볼륨

아프리카 추가 증폭 볼륨을 구현합니다.

// ==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 <mickey90427@naver.com>
// @grant         none
// @license       MIT
// ==/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 });
})();