From 648c126b070fc83ddb66b0353d03c4ad31b87551 Mon Sep 17 00:00:00 2001 From: ilotterytea Date: Sun, 15 Jun 2025 16:14:16 +0400 Subject: feat: audio recording --- public/static/scripts/audiorecorder.js | 210 +++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 public/static/scripts/audiorecorder.js (limited to 'public/static/scripts') diff --git a/public/static/scripts/audiorecorder.js b/public/static/scripts/audiorecorder.js new file mode 100644 index 0000000..b12a2af --- /dev/null +++ b/public/static/scripts/audiorecorder.js @@ -0,0 +1,210 @@ +// getting form upload tabs +const tabs = document.getElementById('form-upload-tabs'); + +// creating an audio button +tabs.innerHTML += ` +
+ +
+`; + +function generateAudioRecorderHTML() { + return ` +
+ + +
+ +
+
+`; +} + +const form = document.getElementById('form-record-upload'); +form.innerHTML = generateAudioRecorderHTML(); + +const startBtn = document.getElementById('record-start-btn'); +const stopBtn = document.getElementById('record-stop-btn'); +const playBtn = document.getElementById('record-play-btn'); +const pauseBtn = document.getElementById('record-pause-btn'); + +const player = document.getElementById('record-player'); +const slider = document.getElementById('record-slider'); +const currentSecond = document.getElementById('record-currentsecond'); +const duration = document.getElementById('record-duration'); + +let playback = null; + +// record functions +let mediaRecorder; +let stream; +let audioChunks = []; +let audioLength = 0; + +async function startRecording() { + // TODO: very poor sound quality + stream = await navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 44100, channelCount: 1 }}); + const options = { mimeType: 'audio/ogg; codecs=opus', audioBitsPerSecond: 128000 }; + if (!MediaRecorder.isTypeSupported(options.mimeType)) { + alert("Your browser doesn't support audio/ogg recording."); + return; + } + + audioLength = 0; + + mediaRecorder = new MediaRecorder(stream, options); + audioChunks = []; + + mediaRecorder.ondataavailable = event => { + if (event.data.size > 0) { + audioChunks.push(event.data); + audioLength++; + } + }; + + mediaRecorder.start(); + startBtn.style.display = 'none'; + stopBtn.style.display = 'block'; + player.style.display = 'none'; + + setFormDetailsVisiblity(false); +} + +function stopRecording() { + mediaRecorder.stop(); + startBtn.style.display = 'block'; + stopBtn.style.display = 'none'; + + if (playback) { + form.removeChild(playback); + playback = null; + } + + mediaRecorder.onstop = () => { + const blob = new Blob(audioChunks, { type: 'audio/ogg; codecs=opus' }); + const file = new File([blob], 'recording.ogg', { type: 'audio/ogg; codecs=opus' }); + + const url = URL.createObjectURL(file); + + playback = document.createElement('audio'); + playback.src = url; + + playback.addEventListener('loadedmetadata', () => { + const d = playback.duration; + slider.max = d; + slider.value = 0; + currentSecond.textContent = formatTimestamp(slider.getAttribute('value')); + duration.textContent = formatTimestamp(d); + }); + + playback.addEventListener('timeupdate', () => { + currentSecond.textContent = formatTimestamp(playback.currentTime); + slider.value = playback.currentTime; + }); + + playback.addEventListener('ended', () => { + playBtn.style.display = 'flex'; + pauseBtn.style.display = 'none'; + currentSecond.textContent = formatTimestamp(0); + slider.value = 0; + }); + + form.appendChild(playback); + + playBtn.style.display = 'flex'; + pauseBtn.style.display = 'none'; + + startBtn.style.display = 'none'; + stopBtn.style.display = 'none'; + player.style.display = 'flex'; + + setFormDetailsVisiblity(true); + + stream.getAudioTracks().forEach(track => { + track.stop(); + }); + + stream = null; + + // attaching the file + if (formFile) { + const dt = new DataTransfer(); + dt.items.add(file); + formFile.files = dt.files; + } + + tabs.setAttribute('disabled', 'true'); + }; +} + +function removeRecording() { + startBtn.style.display = 'block'; + player.style.display = 'none'; + form.removeChild(playback); + formFile.value = ''; + setFormDetailsVisiblity(false); + + tabs.removeAttribute('disabled'); +} + +function playRecord() { + if (playback) playback.play(); + + playBtn.style.display = 'none'; + pauseBtn.style.display = 'flex'; +} + +function pauseRecord() { + if (playback) playback.pause(); + + playBtn.style.display = 'flex'; + pauseBtn.style.display = 'none'; +} + +function rewindRecord() { + currentSecond.textContent = formatTimestamp(slider.value); + if (playback) { + playback.currentTime = slider.value; + playRecord(); + } +} + +function formatTimestamp(timestamp) { + const m = Math.floor(timestamp / 60); + const s = Math.ceil(timestamp % 60); + + return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s +} + +// form +document.getElementById('form-upload').addEventListener('submit', () => { + player.style.display = 'none'; + startBtn.style.display = 'block'; +}); \ No newline at end of file -- cgit v1.2.3