mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-09 17:51:46 +00:00
115 lines
2.9 KiB
JavaScript
115 lines
2.9 KiB
JavaScript
module.exports = (options) => {
|
|
let isSilent = false;
|
|
let hasAudioStarted = false;
|
|
|
|
const smoothing = 0.1;
|
|
const threshold = -100; // DB (-100 = absolute silence, 0 = loudest)
|
|
const interval = 2; // Ms
|
|
const history = 10;
|
|
const speakingHistory = Array.from({ length: history }).fill(0);
|
|
|
|
document.addEventListener(
|
|
'audioCanPlay',
|
|
(e) => {
|
|
const video = document.querySelector('video');
|
|
const { audioContext } = e.detail;
|
|
const sourceNode = e.detail.audioSource;
|
|
|
|
// Use an audio analyser similar to Hark
|
|
// https://github.com/otalk/hark/blob/master/hark.bundle.js
|
|
const analyser = audioContext.createAnalyser();
|
|
analyser.fftSize = 512;
|
|
analyser.smoothingTimeConstant = smoothing;
|
|
const fftBins = new Float32Array(analyser.frequencyBinCount);
|
|
|
|
sourceNode.connect(analyser);
|
|
analyser.connect(audioContext.destination);
|
|
|
|
const looper = () => {
|
|
setTimeout(() => {
|
|
const currentVolume = getMaxVolume(analyser, fftBins);
|
|
|
|
let history = 0;
|
|
if (currentVolume > threshold && isSilent) {
|
|
// Trigger quickly, short history
|
|
for (
|
|
let i = speakingHistory.length - 3;
|
|
i < speakingHistory.length;
|
|
i++
|
|
) {
|
|
history += speakingHistory[i];
|
|
}
|
|
|
|
if (history >= 2) {
|
|
// Not silent
|
|
isSilent = false;
|
|
hasAudioStarted = true;
|
|
}
|
|
} else if (currentVolume < threshold && !isSilent) {
|
|
for (const element of speakingHistory) {
|
|
history += element;
|
|
}
|
|
|
|
if (history == 0 // Silent
|
|
|
|
&& !(
|
|
video.paused
|
|
|| video.seeking
|
|
|| video.ended
|
|
|| video.muted
|
|
|| video.volume === 0
|
|
)
|
|
) {
|
|
isSilent = true;
|
|
skipSilence();
|
|
}
|
|
}
|
|
|
|
speakingHistory.shift();
|
|
speakingHistory.push(0 + (currentVolume > threshold));
|
|
|
|
looper();
|
|
}, interval);
|
|
};
|
|
|
|
looper();
|
|
|
|
const skipSilence = () => {
|
|
if (options.onlySkipBeginning && hasAudioStarted) {
|
|
return;
|
|
}
|
|
|
|
if (isSilent && !video.paused) {
|
|
video.currentTime += 0.2; // In s
|
|
}
|
|
};
|
|
|
|
video.addEventListener('play', () => {
|
|
hasAudioStarted = false;
|
|
skipSilence();
|
|
});
|
|
|
|
video.addEventListener('seeked', () => {
|
|
hasAudioStarted = false;
|
|
skipSilence();
|
|
});
|
|
},
|
|
{
|
|
passive: true,
|
|
},
|
|
);
|
|
};
|
|
|
|
function getMaxVolume(analyser, fftBins) {
|
|
let maxVolume = Number.NEGATIVE_INFINITY;
|
|
analyser.getFloatFrequencyData(fftBins);
|
|
|
|
for (let i = 4, ii = fftBins.length; i < ii; i++) {
|
|
if (fftBins[i] > maxVolume && fftBins[i] < 0) {
|
|
maxVolume = fftBins[i];
|
|
}
|
|
}
|
|
|
|
return maxVolume;
|
|
}
|