Refactoring: move out video contoller

This commit is contained in:
Dejvino 2025-11-13 20:49:54 +01:00
parent 8ea8ad27ce
commit 942ab5e0ee
2 changed files with 113 additions and 112 deletions

View File

@ -48,6 +48,7 @@
<script src="./src/global-variables.js"></script>
<script src="./src/utils.js"></script>
<script src="./src/scene.js"></script>
<script src="./src/video-player.js"></script>
<script src="./src/effects_dust.js"></script>
<script src="./src/effects_flies.js"></script>
<script src="./src/vcr-display.js"></script>
@ -137,118 +138,6 @@
return `${paddedMinutes}:${paddedSeconds}`;
}
// --- Play video by index ---
function playVideoByIndex(index) {
currentVideoIndex = index;
const url = videoUrls[index];
// Dispose of previous texture to free resources
if (videoTexture) {
videoTexture.dispose();
videoTexture = null;
}
if (index < 0 || index >= videoUrls.length) {
console.info('End of playlist reached. Reload tapes to start again.');
screenLight.intensity = 0.0;
tvScreen.material.dispose();
tvScreen.material = new THREE.MeshPhongMaterial({
color: 0x0a0a0a, // Deep black
shininess: 5,
specular: 0x111111
});
tvScreen.material.needsUpdate = true;
isVideoLoaded = false;
lastUpdateTime = -1; // force VCR to redraw
return;
}
videoElement.src = url;
videoElement.muted = true;
videoElement.load();
// Set loop property: only loop if it's the only video loaded
videoElement.loop = false; //videoUrls.length === 1;
videoElement.onloadeddata = () => {
// 1. Create the Three.js texture
videoTexture = new THREE.VideoTexture(videoElement);
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
videoTexture.format = THREE.RGBAFormat;
videoTexture.needsUpdate = true;
// 2. Apply the video texture to the screen mesh
tvScreen.material.dispose();
tvScreen.material = new THREE.MeshBasicMaterial({ map: videoTexture });
tvScreen.material.needsUpdate = true;
// 3. Start playback
videoElement.play().then(() => {
isVideoLoaded = true;
// Use the defined base intensity for screen glow
screenLight.intensity = originalScreenIntensity;
// Initial status message with tape count
console.info(`Playing tape ${currentVideoIndex + 1} of ${videoUrls.length}.`);
}).catch(error => {
screenLight.intensity = originalScreenIntensity * 0.5; // Dim the light if playback fails
console.error(`Playback blocked for tape ${currentVideoIndex + 1}. Click Next Tape to try again.`);
console.error('Playback Error: Could not start video playback.', error);
});
};
videoElement.onerror = (e) => {
screenLight.intensity = 0.1; // Keep minimum intensity for shadow map
console.error(`Error loading tape ${currentVideoIndex + 1}.`);
console.error('Video Load Error:', e);
};
}
// --- Cycle to the next video ---
function playNextVideo() {
// Determine the next index, cycling back to 0 if we reach the end
let nextIndex = currentVideoIndex + 1;
if (nextIndex < videoUrls.length) {
baseTime += videoElement.duration;
}
playVideoByIndex(nextIndex);
}
// --- Video Loading Logic (handles multiple files) ---
function loadVideoFile(event) {
const files = event.target.files;
if (files.length === 0) {
console.info('File selection cancelled.');
return;
}
// 1. Clear previous URLs and revoke object URLs to prevent memory leaks
videoUrls.forEach(url => URL.revokeObjectURL(url));
videoUrls = [];
// 2. Populate the new videoUrls array
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith('video/')) {
videoUrls.push(URL.createObjectURL(file));
}
}
if (videoUrls.length === 0) {
console.info('No valid video files selected.');
return;
}
// 3. Start playback of the first video
console.info(`Loaded ${videoUrls.length} tapes. Starting playback...`);
loadTapeButton.classList.add("hidden");
const startDelay = 5;
console.info(`Video will start in ${startDelay} seconds.`);
setTimeout(() => { playVideoByIndex(0); }, startDelay * 1000);
}
// --- Animation Loop ---
function animate() {

View File

@ -0,0 +1,112 @@
// --- Play video by index ---
function playVideoByIndex(index) {
currentVideoIndex = index;
const url = videoUrls[index];
// Dispose of previous texture to free resources
if (videoTexture) {
videoTexture.dispose();
videoTexture = null;
}
if (index < 0 || index >= videoUrls.length) {
console.info('End of playlist reached. Reload tapes to start again.');
screenLight.intensity = 0.0;
tvScreen.material.dispose();
tvScreen.material = new THREE.MeshPhongMaterial({
color: 0x0a0a0a, // Deep black
shininess: 5,
specular: 0x111111
});
tvScreen.material.needsUpdate = true;
isVideoLoaded = false;
lastUpdateTime = -1; // force VCR to redraw
return;
}
videoElement.src = url;
videoElement.muted = true;
videoElement.load();
// Set loop property: only loop if it's the only video loaded
videoElement.loop = false; //videoUrls.length === 1;
videoElement.onloadeddata = () => {
// 1. Create the Three.js texture
videoTexture = new THREE.VideoTexture(videoElement);
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
videoTexture.format = THREE.RGBAFormat;
videoTexture.needsUpdate = true;
// 2. Apply the video texture to the screen mesh
tvScreen.material.dispose();
tvScreen.material = new THREE.MeshBasicMaterial({ map: videoTexture });
tvScreen.material.needsUpdate = true;
// 3. Start playback
videoElement.play().then(() => {
isVideoLoaded = true;
// Use the defined base intensity for screen glow
screenLight.intensity = originalScreenIntensity;
// Initial status message with tape count
console.info(`Playing tape ${currentVideoIndex + 1} of ${videoUrls.length}.`);
}).catch(error => {
screenLight.intensity = originalScreenIntensity * 0.5; // Dim the light if playback fails
console.error(`Playback blocked for tape ${currentVideoIndex + 1}. Click Next Tape to try again.`);
console.error('Playback Error: Could not start video playback.', error);
});
};
videoElement.onerror = (e) => {
screenLight.intensity = 0.1; // Keep minimum intensity for shadow map
console.error(`Error loading tape ${currentVideoIndex + 1}.`);
console.error('Video Load Error:', e);
};
}
// --- Cycle to the next video ---
function playNextVideo() {
// Determine the next index, cycling back to 0 if we reach the end
let nextIndex = currentVideoIndex + 1;
if (nextIndex < videoUrls.length) {
baseTime += videoElement.duration;
}
playVideoByIndex(nextIndex);
}
// --- Video Loading Logic (handles multiple files) ---
function loadVideoFile(event) {
const files = event.target.files;
if (files.length === 0) {
console.info('File selection cancelled.');
return;
}
// 1. Clear previous URLs and revoke object URLs to prevent memory leaks
videoUrls.forEach(url => URL.revokeObjectURL(url));
videoUrls = [];
// 2. Populate the new videoUrls array
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith('video/')) {
videoUrls.push(URL.createObjectURL(file));
}
}
if (videoUrls.length === 0) {
console.info('No valid video files selected.');
return;
}
// 3. Start playback of the first video
console.info(`Loaded ${videoUrls.length} tapes. Starting playback...`);
loadTapeButton.classList.add("hidden");
const startDelay = 5;
console.info(`Video will start in ${startDelay} seconds.`);
setTimeout(() => { playVideoByIndex(0); }, startDelay * 1000);
}