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
문제: 강의 홈페이지에서 처음 시작시 헤드셋 착용한 상태면 오프닝소리가 너무 커서 귀가 아픔.
처음 시작시 소리를 줄여주는 커스텀 스크립트 작성해서 해결
스크립트
- 초기 소리 0.2로설정(해당 변수만 조절해서 크기소리 조절 가능)
- observer 를 통해 video element 여부확인 및 Log 생성
// ==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에게 대부분의 도움을 받음 내가 한 것은 프로젝트 목적, 로그, 구현 웹 환경종보 제공
- 일반 internal video태그기반 ->작동 안함
- 14만줄 기존 함수 정보제공 후 수정->작동 안함
- Console을 활용한 디버깅 시도.-> No existing video elements found. 제일결정적 원인
- 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 // 모든 하위 노드의 변화를 감지합니다.
});
}