// Define a debug mode variable let debugMode = true; const canvas = document.getElementById("videoCanvas"); const ctx = canvas.getContext("2d"); let videosToLoad = 2 const maxVideosToLoad = 9 const videos = []; let videosLoaded = 0; let aspectRatio = 1; function loadVideos(num) { console.log(`Loading ${num} videos`) while (num > 0) { let video = createVideoElement() video.addEventListener("loadedmetadata", handleVideoLoaded); video.addEventListener("loaded", handleVideoEnded); video.addEventListener("ended", handleVideoEnded); video.src = selectRandomVideo(video) videos.push(video) num-- } while (num < 0) { let video = videos.pop() video.removeEventListener("loadedmetadata", handleVideoLoaded); video.removeEventListener("ended", handleVideoEnded); num++ } } loadVideos(videosToLoad) videos.forEach((video) => { video.addEventListener("loadedmetadata", handleVideoLoaded); video.addEventListener("ended", handleVideoEnded); }); function createVideoElement() { const video = document.createElement("video"); video.autoplay = true; video.muted = true; return video; } function handleVideoLoaded() { videosLoaded++; if (videosLoaded === videos.length) { updateCanvasSize(); drawVideos(); } } function handleVideoEnded(event) { const video = event.target; selectRandomVideo(video); } function drawVideos() { ctx.clearRect(0, 0, canvas.width, canvas.height); let blendModes = ["source-over","overlay","screen"] videos.forEach((video,i) => { // Calculate scaling factor to fit the canvas const scale = Math.max(canvas.width/video.videoWidth, canvas.height/video.videoHeight) // Calculate scaled dimensions const scaledWidth = video.videoWidth * scale const scaledHeight = video.videoHeight * scale // Calculate horizontal and vertical centering offset const offsetX = (canvas.width-scaledWidth)/2 const offsetY = (canvas.height-scaledHeight)/2 // Use default blend mode for first video (i=0), repeat the rest of blendModes if (i === 0) { ctx.globalCompositeOperation = blendModes[0]; } else { ctx.globalCompositeOperation = blendModes[(i - 1) % (blendModes.length - 1) + 1]; } // Draw the current video frame onto the canvas ctx.drawImage(video, offsetX, offsetY, scaledWidth, scaledHeight) // Reset composite operation ctx.globalCompositeOperation = "source-over"; }) // If debugMode is true, draw debug text if (debugMode) { drawDebugText(); } // Request next frame requestAnimationFrame(drawVideos); } function drawDebugText() { // Set font style and color ctx.font = "16px Arial"; ctx.fillStyle = "white"; let corners = [[0, 0], [1, 1], [0, 1], [1, 0]]; // Top-left, bottom-right, top-right, bottom-left let padding = 20 videos.forEach((video, i) => { // Get the corner coordinates for the current video const corner = corners[i]; // Calculate the position of the text in the corner let positionX = corner[0] ? canvas.width : padding let positionY = corner[1] ? canvas.height : padding // Adjust position to ensure text is within the canvas bounds //positionX = Math.max(0, Math.min(positionX, canvas.width - ctx.measureText(getFilename(video.src)).width)); positionY = Math.max(0, Math.min(positionY, canvas.height - padding*3)); // Set text alignment based on corner ctx.textAlign = corner[0] ? "right" : "left" ctx.textBaseline = corner[1] ? "bottom" : "top" // Draw debug text for the video ctx.fillText(getFilename(video.src), positionX, positionY); ctx.fillText(`Dimensions: ${video.videoWidth}x${video.videoHeight} ()`, positionX, positionY + 20); ctx.fillText(formatTime(video.currentTime) + "/" + formatTime(video.duration), positionX, positionY + 40); // Add more debug information as needed }); } // Function to extract filename from full path function getFilename(src) { const parts = src.split('/'); return decodeURIComponent(parts[parts.length - 1].replace(/\%20/g, ' ')); } // Helper function to format time in HH:MM:SS format function formatTime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const remainingSeconds = Math.floor(seconds % 60); return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } function updateCanvasSize() { aspectRatio = Math.max( videos[0].videoWidth / videos[0].videoHeight, videos[1].videoWidth / videos[1].videoHeight ); canvas.width = window.innerWidth; canvas.height = window.innerWidth / aspectRatio; } window.addEventListener("resize", updateCanvasSize); updateCanvasSize() function selectRandomVideo(videoElement) { console.log("selectRandomVideo",videoElement) fetch("/api/videos") .then((response) => response.json()) .then((videoFiles) => { const otherVideo = videos.find((video) => video !== videoElement); let randomVideo; do { const randomIndex = Math.floor(Math.random() * videoFiles.length); randomVideo = videoFiles[randomIndex]; } while (randomVideo === otherVideo); videoElement.src = randomVideo.src; videoElement.play(); return videoElement }); } document.addEventListener('keydown', function(event) { console.log('keyDown',event) // Check if the pressed key is the one you want to bind if (event.key === 'Enter') { debugMode = !debugMode console.log("debugMode:",debugMode) } if (event.key === 'ArrowDown') { loadVideos(-1) } if (event.key === 'ArrowUp') { loadVideos(1) } });