|
|
|
@ -1,72 +1,48 @@ |
|
|
|
// Define a debug mode variable
|
|
|
|
// Define a debug mode variable
|
|
|
|
let debugMode = true |
|
|
|
let debugMode = true; |
|
|
|
|
|
|
|
|
|
|
|
const canvas = document.getElementById("videoCanvas") |
|
|
|
const canvas = document.getElementById("videoCanvas"); |
|
|
|
const ctx = canvas.getContext("2d") |
|
|
|
const ctx = canvas.getContext("2d"); |
|
|
|
|
|
|
|
|
|
|
|
let videosToLoad = 2 |
|
|
|
const videos = [createVideoElement(), createVideoElement()]; |
|
|
|
const maxVideosToLoad = 9 |
|
|
|
let videosLoaded = 0; |
|
|
|
const videos = [] |
|
|
|
let aspectRatio = 1; |
|
|
|
let videosLoaded = 0 |
|
|
|
|
|
|
|
let aspectRatio = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let cachedVideos = [] |
|
|
|
window.addEventListener("DOMContentLoaded", () => { |
|
|
|
|
|
|
|
let previousVideo |
|
|
|
let showText = true |
|
|
|
videos.forEach((video) => { |
|
|
|
|
|
|
|
previousVideo = selectRandomVideo(previousVideo || video) |
|
|
|
function debugLog(...args) { |
|
|
|
}); |
|
|
|
if (debugMode) { |
|
|
|
}) |
|
|
|
console.log(...args) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function loadVideos(num) { |
|
|
|
|
|
|
|
debugLog(`Loading ${num} videos`) |
|
|
|
|
|
|
|
while (num > 0) { |
|
|
|
|
|
|
|
let video = createVideoElement() |
|
|
|
|
|
|
|
video.addEventListener("loadedmetadata", handleVideoLoaded) |
|
|
|
|
|
|
|
video.addEventListener("ended", handleVideoEnded) |
|
|
|
|
|
|
|
video.addEventListener("error", 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++ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
videos.forEach((video) => { |
|
|
|
videos.forEach((video) => { |
|
|
|
video.addEventListener("loadedmetadata", handleVideoLoaded) |
|
|
|
video.addEventListener("loadedmetadata", handleVideoLoaded); |
|
|
|
video.addEventListener("ended", handleVideoEnded) |
|
|
|
video.addEventListener("ended", handleVideoEnded); |
|
|
|
}) |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
function createVideoElement() { |
|
|
|
function createVideoElement() { |
|
|
|
const video = document.createElement("video") |
|
|
|
const video = document.createElement("video"); |
|
|
|
video.autoplay = true |
|
|
|
video.autoplay = true; |
|
|
|
video.muted = true |
|
|
|
video.muted = true; |
|
|
|
return video |
|
|
|
return video; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function handleVideoLoaded() { |
|
|
|
function handleVideoLoaded() { |
|
|
|
videosLoaded++ |
|
|
|
videosLoaded++; |
|
|
|
if (videosLoaded === videos.length) { |
|
|
|
if (videosLoaded === videos.length) { |
|
|
|
updateCanvasSize() |
|
|
|
updateCanvasSize(); |
|
|
|
drawVideos() |
|
|
|
drawVideos(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function handleVideoEnded(event) { |
|
|
|
function handleVideoEnded(event) { |
|
|
|
const video = event.target |
|
|
|
const video = event.target; |
|
|
|
//debugLog(video,event)
|
|
|
|
selectRandomVideo(video); |
|
|
|
selectRandomVideo(video) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function drawVideos() { |
|
|
|
function drawVideos() { |
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height) |
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
|
|
|
|
|
|
let blendModes = ["source-over","overlay","screen"] |
|
|
|
let blendModes = ["source-over","overlay","screen"] |
|
|
|
|
|
|
|
|
|
|
|
@ -84,133 +60,112 @@ function drawVideos() { |
|
|
|
|
|
|
|
|
|
|
|
// Use default blend mode for first video (i=0), repeat the rest of blendModes
|
|
|
|
// Use default blend mode for first video (i=0), repeat the rest of blendModes
|
|
|
|
if (i === 0) { |
|
|
|
if (i === 0) { |
|
|
|
ctx.globalCompositeOperation = blendModes[0] |
|
|
|
ctx.globalCompositeOperation = blendModes[0]; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ctx.globalCompositeOperation = blendModes[(i - 1) % (blendModes.length - 1) + 1] |
|
|
|
ctx.globalCompositeOperation = blendModes[(i - 1) % (blendModes.length - 1) + 1]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Draw the current video frame onto the canvas
|
|
|
|
// Draw the current video frame onto the canvas
|
|
|
|
ctx.drawImage(video, offsetX, offsetY, scaledWidth, scaledHeight) |
|
|
|
ctx.drawImage(video, offsetX, offsetY, scaledWidth, scaledHeight) |
|
|
|
|
|
|
|
|
|
|
|
// Reset composite operation
|
|
|
|
// Reset composite operation
|
|
|
|
ctx.globalCompositeOperation = "source-over" |
|
|
|
ctx.globalCompositeOperation = "source-over"; |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// If showText is true, draw debug text
|
|
|
|
// If debugMode is true, draw debug text
|
|
|
|
if (showText) { |
|
|
|
if (debugMode) { |
|
|
|
drawDebugText() |
|
|
|
drawDebugText(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Request next frame
|
|
|
|
// Request next frame
|
|
|
|
requestAnimationFrame(drawVideos) |
|
|
|
requestAnimationFrame(drawVideos); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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]]; // Top-left, bottom-right, top-right, bottom-left
|
|
|
|
let padding = 20 |
|
|
|
let padding = 20 |
|
|
|
|
|
|
|
|
|
|
|
videos.forEach((video, i) => { |
|
|
|
videos.forEach((video, i) => { |
|
|
|
// Get the corner coordinates for the current video
|
|
|
|
// Get the corner coordinates for the current video
|
|
|
|
const corner = corners[i] |
|
|
|
const corner = corners[i]; |
|
|
|
|
|
|
|
|
|
|
|
// Calculate the position of the text in the corner
|
|
|
|
// Calculate the position of the text in the corner
|
|
|
|
let positionX = corner[0] ? canvas.width : padding |
|
|
|
let positionX = corner[0] ? canvas.width : padding |
|
|
|
let positionY = corner[1] ? canvas.height : padding |
|
|
|
let positionY = corner[1] ? canvas.height : padding |
|
|
|
|
|
|
|
|
|
|
|
// Adjust position to ensure text is within the canvas bounds
|
|
|
|
// 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))
|
|
|
|
//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)) |
|
|
|
positionY = Math.max(0, Math.min(positionY, canvas.height - padding*3)); |
|
|
|
|
|
|
|
|
|
|
|
// Set text alignment based on corner
|
|
|
|
// Set text alignment based on corner
|
|
|
|
ctx.textAlign = corner[0] ? "right" : "left" |
|
|
|
ctx.textAlign = corner[0] ? "right" : "left" |
|
|
|
ctx.textBaseline = corner[1] ? "bottom" : "top" |
|
|
|
ctx.textBaseline = corner[1] ? "bottom" : "top" |
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Function to extract filename from full path
|
|
|
|
// Function to extract filename from full path
|
|
|
|
function getFilename(src) { |
|
|
|
function getFilename(src) { |
|
|
|
const parts = src.split('/') |
|
|
|
const parts = src.split('/'); |
|
|
|
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); |
|
|
|
const minutes = Math.floor((seconds % 3600) / 60) |
|
|
|
const minutes = Math.floor((seconds % 3600) / 60); |
|
|
|
const remainingSeconds = Math.floor(seconds % 60) |
|
|
|
const remainingSeconds = Math.floor(seconds % 60); |
|
|
|
return `${(hours?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')}`; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function updateCanvasSize() { |
|
|
|
function updateCanvasSize() { |
|
|
|
aspectRatio = Math.max( |
|
|
|
aspectRatio = Math.max( |
|
|
|
videos[0].videoWidth / videos[0].videoHeight, |
|
|
|
videos[0].videoWidth / videos[0].videoHeight, |
|
|
|
videos[1].videoWidth / videos[1].videoHeight |
|
|
|
videos[1].videoWidth / videos[1].videoHeight |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
canvas.width = window.innerWidth |
|
|
|
canvas.width = window.innerWidth; |
|
|
|
canvas.height = window.innerWidth / aspectRatio |
|
|
|
canvas.height = window.innerWidth / aspectRatio; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener("resize", updateCanvasSize) |
|
|
|
window.addEventListener("resize", updateCanvasSize); |
|
|
|
|
|
|
|
|
|
|
|
function getSourceFiles() { |
|
|
|
updateCanvasSize() |
|
|
|
debugLog("Getting source files") |
|
|
|
|
|
|
|
return fetch("/api/videos") |
|
|
|
|
|
|
|
.then(response => response.json()) |
|
|
|
|
|
|
|
.then(videoFiles => { |
|
|
|
|
|
|
|
debugLog("Success") |
|
|
|
|
|
|
|
cachedVideos = videoFiles; |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.catch(error => console.error("Error fetching videos:", error)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function selectRandomVideo(videoElement) { |
|
|
|
function selectRandomVideo(videoElement) { |
|
|
|
if (cachedVideos.length) { |
|
|
|
console.log("selectRandomVideo",videoElement) |
|
|
|
const currentSrc = videoElement.src; |
|
|
|
fetch("/api/videos") |
|
|
|
const filteredVideos = cachedVideos.filter(video => video.src !== currentSrc); |
|
|
|
.then((response) => response.json()) |
|
|
|
if (filteredVideos.length > 0) { |
|
|
|
.then((videoFiles) => { |
|
|
|
const randomIndex = Math.floor(Math.random() * filteredVideos.length); |
|
|
|
const otherVideo = videos.find((video) => video !== videoElement); |
|
|
|
const randomVideo = filteredVideos[randomIndex]; |
|
|
|
|
|
|
|
videoElement.src = randomVideo.src; |
|
|
|
let randomVideo; |
|
|
|
} else { |
|
|
|
do { |
|
|
|
debugLog("No other videos available."); |
|
|
|
const randomIndex = Math.floor(Math.random() * videoFiles.length); |
|
|
|
getSourceFiles().then(()=>{ |
|
|
|
randomVideo = videoFiles[randomIndex]; |
|
|
|
selectRandomVideo(videoElement) |
|
|
|
} while (randomVideo === otherVideo); |
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
videoElement.src = randomVideo.src; |
|
|
|
} else { |
|
|
|
videoElement.play(); |
|
|
|
debugLog("Cache empty, doing new request") |
|
|
|
return videoElement |
|
|
|
getSourceFiles().then(()=>{ |
|
|
|
}); |
|
|
|
selectRandomVideo(videoElement) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', function(event) { |
|
|
|
document.addEventListener('keydown', function(event) { |
|
|
|
console.log('keyDown',event) |
|
|
|
|
|
|
|
// Check if the pressed key is the one you want to bind
|
|
|
|
// Check if the pressed key is the one you want to bind
|
|
|
|
if (event.key === 'Enter') { |
|
|
|
if (event.key === 'Enter') { // Change 'Enter' to the desired key
|
|
|
|
showText = !showText |
|
|
|
debugMode = !debugMode |
|
|
|
} |
|
|
|
console.log("debugMode:",debugMode) |
|
|
|
if (event.key === 'ArrowDown') { |
|
|
|
|
|
|
|
loadVideos(-1) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (event.key === 'ArrowUp') { |
|
|
|
}); |
|
|
|
loadVideos(1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getSourceFiles().then(()=>{ |
|
|
|
|
|
|
|
loadVideos(videosToLoad) |
|
|
|
|
|
|
|
updateCanvasSize() |
|
|
|
|
|
|
|
}) |
|
|
|
|