slaeforms/slaeforms/static/videoscript.js

286 lines
12 KiB
JavaScript

const buttonCamera = document.getElementById('buttonCamera');
const buttonRecord = document.getElementById('buttonRecord');
const buttonDelete = document.getElementById('buttonDelete');
const buttonCameraIcon = document.getElementById('buttonCameraIcon');
const buttonRecordIcon = document.getElementById('buttonRecordIcon');
const buttonDeleteIcon = document.getElementById('buttonDeleteIcon');
const countdownText = document.getElementById('countdown')
const videoDisplay = document.getElementById('videoDisplay');
const videoContainer = document.getElementById('videoContainer'); // div that contains the videodisplay
var mediaRecorder = null; // interface of the Media Stream Recording API to record the video stream
var stream = null; // webcam video input stream
let recordedVideoBlob = null; // recorded videodata
let isRecording = false; // false to display record button, true to display stop button
let videoAccess = false; // true if user has given permission to use the webcam
let videotime = 70; // how many seconds video is allowed to be recorded
let timeleft = videotime; // counter for how much time is still left
var countdownTimer; //the timer object that will end the recording if it takes too long
// default video dimensions
let videoHeight = 720;
let videoWidth = 1280;
// handle form submission
//the Video is beeing send together with the form data
document.getElementById("question_form").addEventListener("submit", function (event) {
event.preventDefault(); // Prevent the default form submission
console.log("submit button pressed");
// create a FormData object
const formData = new FormData(event.target);
console.log("form data: ",formData);
// append the recorded video blob to the FormData object
if (recordedVideoBlob) {
console.log("video is available: ", recordedVideoBlob);
formData.append("recordedVideo", recordedVideoBlob, "recordedVideo.webm");
}
console.log("Data to be submitted: ",formData);
console.log("try to send the form and video");
// send the form data and video to the backend
fetch("/send", {
method: "POST",
body: formData
}).then(response => {
// code to handle proper redirection after submit
console.log('Response:', response);
// check if response is a redirect
if (response.redirected) {
console.log("Redirecting to:", response.url);
window.location.href = response.url; // Redirect to the new page
} else {
console.log("No redirect response received.");
}
})
.catch(error => {
console.error('Error:', error);
});
});
// enable/disable video recording feature
async function cameraButton() {
if (!videoAccess) {
console.log("cameraButton case videoAccess = false");
try {
// ask the user for permission to use the webcam
// if given, assign it to "stream"
stream = await navigator.mediaDevices.getUserMedia({
video: true,
});
} catch (error) {
console.log("Error: ", error);
return;
}
console.log("stream is active");
videoAccess = true;
// set the dimensions of the webcam stream to the video display
videoHeight = stream.getVideoTracks()[0].getSettings().height
videoWidth = stream.getVideoTracks()[0].getSettings().width
// calculate the aspec ratio
let aspectratio = (videoHeight / videoWidth) *100;
//console.log("videoHeight: ",videoHeight);
//console.log("videoWidth: ",videoWidth);
//console.log("aspect ratio: ",aspectratio);
//console.log("device: ",stream.getVideoTracks()[0].getSettings().deviceId);
// adjust CSS to make the video fit properly
// this makes sure that there is no buggy "jumping" when the video display source changes
videoContainer.style.setProperty("padding-bottom", "min("+videoHeight+"px,"+aspectratio+"%), 100vh");
//TODO: Solution for this part:
// If the video is vertical, I need to set the width to 0, the max-height to 100% and do the padding on the width, so turn the code around
//This should always make the video fitt
// adjust the max width for horizontal and vertical video input
if (videoHeight > videoWidth){ //hochkant video
// I did this originally to display vertical video on a horizontal screen properly (video should not be higher than the screem)
// but now I do this by adjusting the paddint to be at most 100vh, so this whole part should be useless now
// But a new problem could be if I do too little padding and the ratio is lost because of it, so actually I also need to adjust the width
videoContainer.style.setProperty("max-width", "min(80%,576)"); // maybe actually use the screen height here: instead of 80% maybe 80vh
}else{ //normal, horizontal
videoContainer.style.setProperty("max-width", "100%");
}
// show the webcam input stream on the video display
videoDisplay.srcObject = stream;
// change the icon to indicate the disable option
buttonCameraIcon.src = ICON_PATHS.cameraofficon;
buttonCameraIcon.alt = "Camera-off Icon";
// display the elements for the video recording
buttonRecord.style.display = 'inline-block';
buttonDelete.style.display = 'inline-block';
videoDisplay.style.display = 'block';
videoContainer.style.display = 'block';
videoDisplay.classList.add("videomirror");
// initialize MediaRecorder, give it the webcam stream as input to record
mediaRecorder = new MediaRecorder(stream, {
mimeType: "video/webm",
audioBitsPerSecond: 0,
videoBitsPerSecond: 1900000, // Standard bitrate for video is 2,5 mbps
});
// when data is available at the mediaRecorder (this means the recording has ended, since I have not specified time intervalls)
// save the data in "recordedVideoBlob"
mediaRecorder.addEventListener("dataavailable", (event) => {
console.log("Data available Event triggered");
if (event.data.size > 0) {
recordedVideoBlob = event.data;
console.log("Data available:", recordedVideoBlob);
} else {
console.log("No Data available");
}
});
// when recording is stopped, display the recorded video
// TODO possibly replace this and just add it to the dataavailable event
// TODO this would ensure proper order in a concurrent scenario (the stop code here can only be executed after the dataavailable code happened)
// TODO part of it could also go to the record button function
mediaRecorder.addEventListener("stop", () => {
if (recordedVideoBlob) {
videoDisplay.srcObject = null; //remove the stream as input
videoDisplay.src = URL.createObjectURL(recordedVideoBlob); // create a url for the recorded video and set it as input
videoDisplay.controls = true; // display video controls
videoDisplay.pause(); // pause, so that it doesn't immediately play, TODO maybe disable autoplay?
// TODO maybe move this to the record button function
buttonRecordIcon.src = ICON_PATHS.recordicon; //change the icon of the record button back
buttonRecordIcon.alt = 'Record Icon';
isRecording = false;
console.log('Recording stopped');
console.log("Src path:", videoDisplay.src);
}
});
} else {
// -> the user disabled the videorecording feature
console.log("cameraButton case videoAccess = true");
stream.getTracks().forEach(track => track.stop()); // stop all tracks to release the camera
stream = null;
videoAccess = false;
// change the icon and hide all the elements again
buttonCameraIcon.src = ICON_PATHS.cameraicon;
buttonCameraIcon.alt = "Camera Icon";
buttonRecord.style.display = 'none';
buttonDelete.style.display = 'none';
videoDisplay.style.display = 'none';
videoContainer.style.display = 'none';
}
console.log("camera button function ends");
}
function recordButton() {
console.log("recordButton pressed");
if (!isRecording) {
// a new recording starts
console.log("recordButton pressed case isRecording = false");
deleteButton(); //delete previous video
videoDisplay.classList.add("videomirror"); // mirror the video while recording, for a more natural experience
buttonDelete.setAttribute("disabled", ""); // can't delete during recording
buttonDeleteIcon.classList.add("buttondisable"); // delete button icon indicates that it is disabled
videoDisplay.src = null; // get rid of the previous video on the display
videoDisplay.srcObject = stream; // set webcam stream as input for the video display
videoDisplay.controls = false; // hide the video controls durin recording, because they are confusing
mediaRecorder.start(); // start recording
timeleft = videotime;
countdownTimer = setInterval(countdown, 1000) //stop the recording after "videotime" Seconds
console.log("video bitrate = ",mediaRecorder.videoBitsPerSecond);
// change icon to indicate "stop"
buttonRecordIcon.src = ICON_PATHS.stopicon;
buttonRecordIcon.alt = 'Stop Icon';
isRecording = true;
console.log('Recording started');
} else {
// recording got stopped
console.log("recordButton pressed case isRecording = true");
clearInterval(countdownTimer)
stopRecording()
}
}
function stopRecording() {
mediaRecorder.stop(); // stop recording
videoDisplay.classList.remove("videomirror"); // don't mirror the videodisplay anymore
clearInterval(countdownTimer);
console.log("recording stops");
// enable the deletebutton again
buttonDelete.removeAttribute("disabled");
buttonDeleteIcon.classList.remove("buttondisable");
}
function timerStop() {
// recording got stopped by timer
console.log("timer stopped the recording");
clearInterval(countdownTimer);
stopRecording();
}
function countdown() {
if(timeleft <= 0){
countdownText.textContent = "";
timerStop();
clearInterval(countdownTimer);
return;
}
if(timeleft >= 60){
r = timeleft - 60;
if(r< 10){
countdownText.textContent = "01:0"+r;
}else{
countdownText.textContent = "01:"+r;
}
}else{
if(timeleft< 10){
countdownText.textContent = "00:0"+timeleft;
}else{
countdownText.textContent = "00:"+timeleft;
}
}
timeleft -= 1;
}
function deleteButton() {
// delete the recorded video
videoDisplay.controls = false;
videoDisplay.srcObject = stream; // set webcam stream as source for the video display again
recordedVideoBlob = null
videoDisplay.classList.add("videomirror"); // mirror the video display during live feed again
// disable the deletebutton again
buttonDelete.setAttribute("disabled", "");
buttonDeleteIcon.classList.add("buttondisable");
}