/** * Focus Video Player * Lightweight video player for focus interruption sessions * Extends BaseVideoPlayer with minimal controls for background video */ class FocusVideoPlayer extends BaseVideoPlayer { constructor(containerSelector) { // Initialize with minimal features for focus sessions super(containerSelector, { showControls: true, autoHide: false, // Keep controls visible for focus session showProgress: false, // No progress bar for continuous playback showVolume: true, showFullscreen: false, showQuality: false, showSpeed: false, keyboardShortcuts: false, // Disable to not interfere with game minimal: true, initialVolume: 0.5 }); // Focus-specific properties this.videoLibrary = []; this.currentVideoIndex = 0; this.isActive = false; this.autoPlayNext = true; this.initializeFocusElements(); this.attachFocusEventListeners(); } initializeFocusElements() { // Focus-specific elements this.videoInfo = this.container.querySelector('#video-info') || this.container.querySelector('.video-info'); this.volumeDisplay = document.getElementById('focus-volume-display'); // Map focus video elements to BaseVideoPlayer expected IDs this.mapFocusElementsToBasePlayer(); } /** * Map existing focus video elements to BaseVideoPlayer control structure */ mapFocusElementsToBasePlayer() { // Find the focus volume slider and map it to what BaseVideoPlayer expects const focusVolumeSlider = document.getElementById('focus-video-volume'); if (focusVolumeSlider) { // Add the ID that BaseVideoPlayer looks for focusVolumeSlider.id = 'focus-video-volume'; // Keep original focusVolumeSlider.classList.add('volume-slider'); // Add class BaseVideoPlayer looks for // Manually assign to controls since BaseVideoPlayer already initialized if (this.controls) { this.controls.volume = focusVolumeSlider; console.log('🧘 🎛️ Mapped focus volume slider to BaseVideoPlayer controls'); } } } attachFocusEventListeners() { if (!this.videoElement) return; // Auto-play next video when current ends this.videoElement.addEventListener('ended', () => { if (this.isActive && this.autoPlayNext) { console.log('🧘 🎬 Video ended, playing next...'); setTimeout(() => this.playNextVideo(), 500); } }); // Enhanced error handling for focus sessions this.videoElement.addEventListener('error', (e) => this.handleFocusVideoError(e)); // Volume control with display update const focusVolumeSlider = document.getElementById('focus-video-volume'); if (focusVolumeSlider && this.volumeDisplay) { focusVolumeSlider.addEventListener('input', (e) => { const volume = e.target.value / 100; this.setVolume(volume); this.volumeDisplay.textContent = Math.round(e.target.value) + '%'; console.log(`🧘 🎛️ Focus volume changed to: ${Math.round(e.target.value)}%`); }); console.log('🧘 🎛️ Focus volume control event listener attached'); } } async initializeVideoLibrary(videoManager) { if (!videoManager) { console.warn('🧘 ⚠️ Video manager not available, focus videos disabled'); return; } console.log('🧘 🔍 Debugging video manager:', videoManager); this.videoLibrary = []; // Check if videoManager has videoLibrary structure if (videoManager.videoLibrary) { console.log('🧘 📚 Video library structure found:', videoManager.videoLibrary); const categories = ['task', 'background', 'reward', 'punishment']; for (const category of categories) { const videos = videoManager.videoLibrary[category] || []; this.videoLibrary.push(...videos); console.log(`🧘 📹 Found ${videos.length} videos in ${category} category`); if (videos.length > 0) { console.log(`🧘 📋 First video in ${category}:`, videos[0]); } } } else if (videoManager.getVideosByCategory) { // Fallback for different video manager implementations const categories = ['task', 'background', 'reward']; for (const category of categories) { const videos = videoManager.getVideosByCategory(category) || []; this.videoLibrary.push(...videos); } } else { console.warn('🧘 ⚠️ Video manager structure not recognized'); console.log('🧘 🔍 Available methods:', Object.getOwnPropertyNames(videoManager)); } console.log(`🧘 🎬 Initialized focus video library with ${this.videoLibrary.length} videos`); if (this.videoLibrary.length === 0) { console.warn('🧘 ⚠️ No videos found in any category, focus videos will be disabled'); this.hideVideoContainer(); } } startFocusSession() { if (this.videoLibrary.length === 0) { console.warn('🧘 ⚠️ No videos available for focus session'); this.hideVideoContainer(); return; } this.isActive = true; this.showVideoContainer(); this.playNextVideo(); console.log('🧘 🎬 Focus video session started'); } stopFocusSession() { this.isActive = false; this.pause(); this.hideVideoContainer(); console.log('🧘 🎬 Focus video session stopped'); } playNextVideo() { if (!this.isActive || this.videoLibrary.length === 0) return; // Select random video const randomIndex = Math.floor(Math.random() * this.videoLibrary.length); this.currentVideoIndex = randomIndex; const videoFile = this.videoLibrary[randomIndex]; if (videoFile && videoFile.path) { console.log(`🧘 🎬 Playing focus video: ${videoFile.name}`); this.loadVideo(videoFile.path, true); // Auto-play enabled this.updateVideoInfo(videoFile); } else { console.warn('🧘 ⚠️ Invalid video file, skipping to next'); setTimeout(() => this.playNextVideo(), 1000); } } updateVideoInfo(videoFile) { if (this.videoInfo && videoFile) { const duration = videoFile.duration ? ` (${this.formatTime(videoFile.duration)})` : ''; this.videoInfo.textContent = `${videoFile.name}${duration}`; } } handleFocusVideoError(event) { if (!this.isActive) { console.log('🧘 📹 Video error after session ended, ignoring'); return; } const error = this.videoElement.error; let errorMessage = 'Unknown video error'; if (error) { switch (error.code) { case 1: errorMessage = 'Video loading aborted'; break; case 2: errorMessage = 'Network error'; break; case 3: errorMessage = 'Video decoding error'; break; case 4: errorMessage = 'Video format not supported'; break; default: errorMessage = `Video error code: ${error.code}`; } } console.warn(`🧘 ⚠️ Video error (${errorMessage}), skipping to next video`); if (this.videoInfo) { this.videoInfo.textContent = `Error: ${errorMessage} - Loading next video...`; } // Try next video after short delay setTimeout(() => this.playNextVideo(), 2000); } showVideoContainer() { if (this.container) { this.container.style.display = 'block'; } } hideVideoContainer() { if (this.container) { this.container.style.display = 'none'; } } // Override base class showError for focus session context showError(message) { console.error(`🧘 📺 ${message}`); if (this.videoInfo) { this.videoInfo.textContent = message; } this.hideLoading(); } // Override volume setting to update focus display setVolume(volume) { super.setVolume(volume); // Update focus-specific elements if (this.volumeDisplay) { this.volumeDisplay.textContent = Math.round(volume * 100) + '%'; } // Update focus volume slider const focusVolumeSlider = document.getElementById('focus-video-volume'); if (focusVolumeSlider) { focusVolumeSlider.value = Math.round(volume * 100); } } // Cleanup method for focus session end destroy() { this.stopFocusSession(); super.destroy(); console.log('🧘 📺 FocusVideoPlayer destroyed'); } } // Export for use in other modules if (typeof module !== 'undefined' && module.exports) { module.exports = FocusVideoPlayer; } // Make available globally for browser use if (typeof window !== 'undefined') { window.FocusVideoPlayer = FocusVideoPlayer; }