320.30 b

Description: The opening sound on the some lecture homepage is too loud and hurts my ears when I wear a headset. I wrote a custom script to reduce the sound on the first startup.

#300#Applications#320#Frontend#320.30#JavaScript#320.30 b#Fix_too_loud_sound_at_video_startup_with_headphones_on

문제: 강의 홈페이지에서 처음 시작시 헤드셋 착용한 상태면 오프닝소리가 너무 커서 귀가 아픔.

처음 시작시 소리를 줄여주는 커스텀 스크립트 작성해서 해결

스크립트

// ==UserScript==
// @name         Auto Volume Control for Web Player
// @namespace    http://tampermonkey.net/
// @version      1.11
// @description  Automatically adjusts volume on specific web player pages.
// @match        *://www.boostcourse.org/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log('Tampermonkey script is running.');

    function setVolume(element) {
        if (element) {
            console.log('Setting volume to 20% for:', element);
            element.volume = 0.2; // Volume set to 20%
        }
    }

    // Function to add volume control to a video element
    function addVolumeControl(element) {
        if (element.tagName === 'VIDEO' && element.classList.contains('webplayer-internal-video')) {
            element.addEventListener('play', () => {
                console.log('Play event detected for:', element);
                setVolume(element);
            });
            element.addEventListener('volumechange', () => {
                console.log('Volume change detected for:', element, 'New volume:', element.volume);
                if (element.volume !== 0.2) {
                    setVolume(element); // Reapply volume if changed
                }
            });
            element.addEventListener('loadedmetadata', () => {
                console.log('Loaded metadata event detected for:', element);
                setVolume(element);
            });
            console.log('Adding volume control to:', element);
            setVolume(element); // Set volume immediately
        }
    }

    // Function to observe for new video elements
    function observeMediaElements() {
        const observer = new MutationObserver(mutations => {
            let videoElementFound = false;
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) {
                        if (node.tagName === 'VIDEO' && node.classList.contains('webplayer-internal-video')) {
                            console.log('New video element detected:', node);
                            addVolumeControl(node);
                            videoElementFound = true;
                        }
                        // Check for video elements within added nodes
                        node.querySelectorAll('video.webplayer-internal-video').forEach(videoNode => {
                            console.log('New video element detected within node:', videoNode);
                            addVolumeControl(videoNode);
                            videoElementFound = true;
                        });
                    }
                });
            });

            // Stop observing if video element is found
            if (videoElementFound) {
                console.log('Video element found, disconnecting observer.');
                observer.disconnect();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // Set volume for existing media elements
    const existingVideos = document.querySelectorAll('.webplayer-internal-video');
    if (existingVideos.length > 0) {
        console.log('Existing video elements found:', existingVideos);
        existingVideos.forEach(addVolumeControl);
    } else {
        console.log('No existing video elements found, starting observer.');
        // Observe for new media elements
        observeMediaElements();
    }
})();

문제해결흐름

Chatgpt에게 대부분의 도움을 받음 내가 한 것은 프로젝트 목적, 로그, 구현 웹 환경종보 제공

  1. 일반 internal video태그기반 ->작동 안함
  2. 14만줄 기존 함수 정보제공 후 수정->작동 안함
  3. Console을 활용한 디버깅 시도.-> No existing video elements found. 제일결정적 원인
  4. MutationObserver를 통해 태그 유무 확인 후 스크립트 동작으로 변경->성공

문제 해결의 결정적 계기:
해당 로그로부터 예상해보면 커스텀 스크립트가 비디오가 실행되기전 한 번만 실행돼서 적용이 안되는 것으로 예상. 그래서 태그 유무를 5초마다 ㅎ학인하여 감지시 스크립트 동작하는 방법으로 수정함.

MutationObserver를 사용하여 비디오 요소가 페이지 로드 후 동적으로 추가되는 경우를 감지.
페이지 로드 시점에 존재하지 않는 비디오 요소를 감지하기 위해 Observer를 설정.
비디오 요소가 감지되면 볼륨을 설정하고, 더 이상 감지할 필요가 없으면 Observer를 해제.

최신 코드 및 설명:

비디오 요소를 감지하고 볼륨을 설정한 후, MutationObserver를 해제하여 불필요한 감지를 중지.

function observeMediaElements() {
    // MutationObserver 인스턴스를 생성하여 DOM 변경 사항을 감지할 수 있도록 합니다.
    const observer = new MutationObserver(mutations => {
        let videoElementFound = false;  // 비디오 요소가 발견되었는지 여부를 추적하기 위한 변수입니다.

        // DOM의 변경 사항이 포함된 mutations 배열을 순회합니다.
        mutations.forEach(mutation => {
            // mutation 객체의 addedNodes 속성은 추가된 노드들을 포함합니다.
            mutation.addedNodes.forEach(node => {
                // 추가된 노드가 요소 노드(태그 요소)인지 확인합니다.
                if (node.nodeType === 1) {
                    // 추가된 노드가 비디오 요소이고, 특정 클래스를 가지고 있는지 확인합니다.
                    if (node.tagName === 'VIDEO' && node.classList.contains('webplayer-internal-video')) {
                        console.log('New video element detected:', node);
                        addVolumeControl(node);  // 비디오 요소에 볼륨 조절 기능을 추가합니다.
                        videoElementFound = true;  // 비디오 요소가 발견되었음을 표시합니다.
                    }
                    // 추가된 노드 내부에 비디오 요소가 있는지 확인합니다.
                    node.querySelectorAll('video.webplayer-internal-video').forEach(videoNode => {
                        console.log('New video element detected within node:', videoNode);
                        addVolumeControl(videoNode);  // 내부 비디오 요소에 볼륨 조절 기능을 추가합니다.
                        videoElementFound = true;  // 비디오 요소가 발견되었음을 표시합니다.
                    });
                }
            });
        });

        // 비디오 요소가 하나라도 발견되면 더 이상 관찰할 필요가 없으므로 observer를 해제합니다.
        if (videoElementFound) {
            console.log('Video element found, disconnecting observer.');
            observer.disconnect();
        }
    });

    // observer를 시작합니다. document.body에서 자식 노드의 추가나 변화를 감지합니다.
    observer.observe(document.body, {
        childList: true,  // 직계 자식의 변화를 감지합니다.
        subtree: true     // 모든 하위 노드의 변화를 감지합니다.
    });
}

bosst코스 소리크기조절 스크립트해결.png