Расширение для гугл хром, режим моно для звука
Доброй ночи, вот решил написать для себя расширение для Гугл хром, просто мне надоели школьники на Ютубе которые в одно ухо только звук записывают. Подскажите как мне написать расширение чтобы JavaScript обращался к звуковой дорожке, чтобы она передавала звук в 2 уха. Предложения просто найти сторонние расширения отклоняются сразу, иначе бы я не просил помощи, как минимум мне интересно как это сделать и получить опыт работы в создании расширений, спасибо за отклики!
content.js:(function () {
let audioContext = null;
let mediaSourceMap = new Map();
function findActiveAudioContexts() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
return audioContext;
}
const ctx = findActiveAudioContexts();
function adjustVolume(media, volumeLimit, boostVolume) {
if (!mediaSourceMap.has(media)) {
const source = ctx.createMediaElementSource(media);
mediaSourceMap.set(media, source);
const gainNode = ctx.createGain();
source.connect(gainNode);
gainNode.connect(ctx.destination);
media.volume = Math.min(volumeLimit / 100, 1);
if (boostVolume > 0) {
gainNode.gain.setValueAtTime(Math.pow(10, boostVolume / 20), ctx.currentTime);
}
}
}
function enableMono(media) {
const source = ctx.createMediaElementSource(media);
const leftGain = ctx.createGain();
const rightGain = ctx.createGain();
// Проверка, какой канал активен
leftGain.gain.value = media.volume > 0 ? 1 : 0; // Если звук есть, оставляем его
rightGain.gain.value = media.volume > 0 ? 1 : 0; // Если звук есть, оставляем его
// Подключение источников
source.connect(leftGain);
source.connect(rightGain);
// Создаем gainNode для контроля общего уровня громкости
const gainNode = ctx.createGain();
leftGain.connect(gainNode);
rightGain.connect(gainNode);
gainNode.connect(ctx.destination);
media.play();
}
chrome.runtime.onMessage.addListener((message) => {
if (message.type === 'applyVolumeSettings') {
const { volumeLimit, boostVolume, monoEnabled } = message;
const mediaElements = document.querySelectorAll('audio, video');
mediaElements.forEach(media => {
adjustVolume(media, volumeLimit, boostVolume);
// Включение моно режима, если он активирован
if (monoEnabled) {
enableMono(media);
}
});
}
});
})();
popup.js:document.addEventListener('DOMContentLoaded', () => {
const volumeLimitInput = document.getElementById('volumeLimit');
const volumeInput = document.getElementById('volumeInput');
const boostVolumeInput = document.getElementById('boostVolume');
const boostInput = document.getElementById('boostInput');
const monoCheckbox = document.getElementById('monoCheckbox');
const saveSettings = document.getElementById('saveSettings');
const siteLabel = document.getElementById('siteName');
const volumeWarning = document.getElementById('volumeWarning');
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const url = new URL(tabs[0].url);
const domain = url.hostname;
let siteType = 'Other Site';
if (domain.includes('youtube.com')) siteType = 'YouTube';
if (domain.includes('vk.com')) siteType = 'VK';
siteLabel.textContent = siteType;
chrome.storage.sync.get([siteType], (data) => {
const settings = data[siteType] || { volumeLimit: 75, boostVolume: 0, monoEnabled: false };
volumeLimitInput.value = settings.volumeLimit || 75;
volumeInput.value = settings.volumeLimit || 75;
boostVolumeInput.value = settings.boostVolume || 0;
boostInput.value = settings.boostVolume || 0;
monoCheckbox.checked = settings.monoEnabled || false;
updateVolumeWarning(settings.volumeLimit || 75);
});
});
volumeLimitInput.addEventListener('input', () => {
volumeInput.value = volumeLimitInput.value;
updateVolumeWarning(volumeLimitInput.value);
});
boostVolumeInput.addEventListener('input', () => {
boostInput.value = boostVolumeInput.value;
});
saveSettings.addEventListener('click', () => {
const volumeLimit = parseInt(volumeLimitInput.value);
const boostVolume = parseInt(boostVolumeInput.value);
const monoEnabled = monoCheckbox.checked;
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const url = new URL(tabs[0].url);
const domain = url.hostname;
let siteType = 'Other Site';
if (domain.includes('youtube.com')) siteType = 'YouTube';
if (domain.includes('vk.com')) siteType = 'VK';
const settings = { volumeLimit, boostVolume, monoEnabled };
chrome.storage.sync.set({ [siteType]: settings }, () => {
console.log('Settings saved for', siteType);
});
applySettingsToPage(volumeLimit, boostVolume, monoEnabled, tabs[0].id);
});
});
function updateVolumeWarning(volume) {
if (volume > 85) {
volumeWarning.textContent = "Опасно! Уровень звука выше 85 дБ может быть вреден для слуха.";
} else {
volumeWarning.textContent = "";
}
}
function applySettingsToPage(volumeLimit, boostVolume, monoEnabled, tabId) {
chrome.scripting.executeScript({
target: { tabId: tabId },
func: (volumeLimit, boostVolume, monoEnabled) => {
const mediaElements = document.querySelectorAll('audio, video');
mediaElements.forEach(media => {
media.volume = Math.min(volumeLimit / 100, 1);
if (boostVolume > 0) {
let boostFactor = boostVolume / 100; // Преобразуем в коэффициент
media.volume = Math.min(media.volume * (1 + boostFactor), 6); // Максимум 600%
}
if (monoEnabled) {
enableMono(media);
}
});
},
args: [volumeLimit, boostVolume, monoEnabled]
});
}
});
background.js:
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.sync.set({
YouTube: { volumeLimit: 75, boostVolume: 0, monoEnabled: false },
VK: { volumeLimit: 75, boostVolume: 0, monoEnabled: false },
'Other Site': { volumeLimit: 75, boostVolume: 0, monoEnabled: false }
});
});
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SoundFixer</title>
<style>
body {
font-family: Arial, sans-serif;
width: 300px;
padding: 10px;
background-color: #f0f0f0;
color: #333;
}
.vertical-slider-container {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
}
button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<h1>SoundFixer</h1>
<div>Текущий сайт: <span id="siteName">Other Site</span></div>
<div class="vertical-slider-container">
<label for="volumeLimit">Пиковая громкость (0-100 дБ):</label>
<input type="range" id="volumeLimit" min="0" max="100" value="75">
<input type="number" id="volumeInput" min="0" max="100" value="75">
</div>
<div class="vertical-slider-container">
<label for="boostVolume">Усиление громкости (0-600%):</label>
<input type="range" id="boostVolume" min="0" max="600" value="0">
<input type="number" id="boostInput" min="0" max="600" value="0">
</div>
<div class="vertical-slider-container">
<label for="monoCheckbox">Моно режим:</label>
<input type="checkbox" id="monoCheckbox">
</div>
<button id="saveSettings">Сохранить настройки</button>
<div id="volumeWarning" style="color: red;"></div>
<script src="popup.js"></script>
</body>
</html>
<!--- Содержимое Манифеста manifest.json
{
"manifest_version": 3,
"name": "SoundFixer",
"version": "1.0",
"permissions": ["activeTab", "scripting", "storage"],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
}
}
--->