|
|
|
@ -40,74 +40,44 @@ function handleVideoEnded(event) { |
|
|
|
selectRandomVideo(video); |
|
|
|
selectRandomVideo(video); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Function to extract filename from full path and unescape it
|
|
|
|
function drawVideos() { |
|
|
|
function extractFilename(src) { |
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
// Split the path by '/'
|
|
|
|
|
|
|
|
const parts = src.split('/'); |
|
|
|
let blendModes = ["source-over","overlay","screen"] |
|
|
|
// Get the last part of the path (filename)
|
|
|
|
|
|
|
|
const filename = parts[parts.length - 1]; |
|
|
|
videos.forEach((video,i) => { |
|
|
|
// Unescape the filename and replace '%20' with whitespace
|
|
|
|
// Calculate scaling factor to fit the canvas
|
|
|
|
return decodeURIComponent(filename.replace(/\%20/g, ' ')); |
|
|
|
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 to draw debug text on the canvas
|
|
|
|
function drawDebugText() { |
|
|
|
function drawDebugText() { |
|
|
|
// Set font style and color
|
|
|
|
// Set font style and color
|
|
|
|
ctx.font = "16px Arial"; |
|
|
|
ctx.font = "16px Arial"; |
|
|
|
ctx.fillStyle = "white"; |
|
|
|
ctx.fillStyle = "white"; |
|
|
|
|
|
|
|
|
|
|
|
let corners = [[0, 0], [1, 1], [0, 1], [1, 0]]; // Top-left, bottom-right, top-right, bottom-left
|
|
|
|
let corners = [[0,0],[1,1],[0,1],[1,0]]; |
|
|
|
let padding = 20 |
|
|
|
let padding = 20; |
|
|
|
|
|
|
|
|
|
|
|
videos.forEach((video,i) => { |
|
|
|
videos.forEach((video,i) => { |
|
|
|
// Get the corner coordinates for the current video
|
|
|
|
//console.log("Drawing debug text for video",i,video);
|
|
|
|
const corner = corners[i]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate the position of the text in the corner
|
|
|
|
let corner = corners[i]; |
|
|
|
let positionX = corner[0] ? canvas.width : padding |
|
|
|
let positionX = corner[0] === 0 ? padding : canvas.width - padding; |
|
|
|
let positionY = corner[1] ? canvas.height : padding |
|
|
|
let positionY = corner[1] === 0 ? padding : canvas.height - padding; |
|
|
|
|
|
|
|
|
|
|
|
// Adjust position to ensure text is within the canvas bounds
|
|
|
|
// Adjust position for bottom right corner to stay within canvas bounds
|
|
|
|
//positionX = Math.max(0, Math.min(positionX, canvas.width - ctx.measureText(getFilename(video.src)).width));
|
|
|
|
if (corner[0] === 1 && positionY + 40 > canvas.height) { |
|
|
|
positionY = Math.max(0, Math.min(positionY, canvas.height - padding*3)); |
|
|
|
positionY = canvas.height - 40; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Set text alignment based on corner
|
|
|
|
// Set text alignment based on corner
|
|
|
|
ctx.textAlign = corner[0] ? "right" : "left" |
|
|
|
ctx.textAlign = corner[0] === 0 ? "left" : "right"; |
|
|
|
ctx.textBaseline = corner[1] ? "bottom" : "top" |
|
|
|
ctx.textBaseline = corner[1] === 0 ? "top" : "bottom"; |
|
|
|
|
|
|
|
|
|
|
|
// Draw debug text for the video
|
|
|
|
// Draw debug text for the video
|
|
|
|
ctx.fillText(getFilename(video.src), positionX, positionY); |
|
|
|
ctx.fillText(getFilename(video.src), positionX, positionY); |
|
|
|
ctx.fillText(`Dimensions: ${video.videoWidth}x${video.videoHeight} ()`, positionX, positionY + 20); |
|
|
|
ctx.fillText("Dimensions: " + video.videoWidth + "x" + video.videoHeight, positionX, positionY + 20); |
|
|
|
ctx.fillText(formatTime(video.currentTime) + "/" + formatTime(video.duration), positionX, positionY + 40); |
|
|
|
ctx.fillText(formatTime(video.currentTime) + "/" + formatTime(video.duration), positionX, positionY + 40); |
|
|
|
// Add more debug information as needed
|
|
|
|
// Add more debug information as needed
|
|
|
|
}); |
|
|
|
}); |
|
|
|
@ -121,6 +91,7 @@ function getFilename(src) { |
|
|
|
return decodeURIComponent(parts[parts.length - 1].replace(/\%20/g, ' ')); |
|
|
|
return decodeURIComponent(parts[parts.length - 1].replace(/\%20/g, ' ')); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Helper function to format time in HH:MM:SS format
|
|
|
|
// Helper function to format time in HH:MM:SS format
|
|
|
|
function formatTime(seconds) { |
|
|
|
function formatTime(seconds) { |
|
|
|
const hours = Math.floor(seconds / 3600); |
|
|
|
const hours = Math.floor(seconds / 3600); |
|
|
|
@ -129,6 +100,42 @@ function formatTime(seconds) { |
|
|
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; |
|
|
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Modify the drawVideos function to include debug text drawing
|
|
|
|
|
|
|
|
function drawVideos() { |
|
|
|
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Resize the canvas to accommodate both videos side by side
|
|
|
|
|
|
|
|
canvas.width = Math.max(videos[0].videoWidth, videos[1].videoWidth); |
|
|
|
|
|
|
|
canvas.height = Math.max(videos[0].videoHeight, videos[1].videoHeight); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate positions for each video
|
|
|
|
|
|
|
|
const video1X = (canvas.width - videos[0].videoWidth) / 2; |
|
|
|
|
|
|
|
const video1Y = (canvas.height - videos[0].videoHeight) / 2; |
|
|
|
|
|
|
|
const video2X = (canvas.width - videos[1].videoWidth) / 2; |
|
|
|
|
|
|
|
const video2Y = (canvas.height - videos[1].videoHeight) / 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw video 1
|
|
|
|
|
|
|
|
ctx.drawImage(videos[0], video1X, video1Y, videos[0].videoWidth, videos[0].videoHeight); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set composite operation to overlay
|
|
|
|
|
|
|
|
ctx.globalCompositeOperation = "overlay"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw video 2
|
|
|
|
|
|
|
|
ctx.drawImage(videos[1], video2X, video2Y, videos[1].videoWidth, videos[1].videoHeight); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reset composite operation
|
|
|
|
|
|
|
|
ctx.globalCompositeOperation = "source-over"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw debug text if debug mode is enabled
|
|
|
|
|
|
|
|
if (debugMode) { |
|
|
|
|
|
|
|
drawDebugText(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Request next frame
|
|
|
|
|
|
|
|
requestAnimationFrame(drawVideos); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateCanvasSize() { |
|
|
|
function updateCanvasSize() { |
|
|
|
aspectRatio = Math.max( |
|
|
|
aspectRatio = Math.max( |
|
|
|
videos[0].videoWidth / videos[0].videoHeight, |
|
|
|
videos[0].videoWidth / videos[0].videoHeight, |
|
|
|
|