/** * Enhanced Video Player for leaksdaily * Optimized for phone.mp4 and pc.mp4 with custom controls and seeking */ class EnhancedVideoPlayer { constructor(videoElement, options = {}) { this.video = videoElement; this.container = null; this.controls = null; this.isPlaying = false; this.isDragging = false; this.currentQuality = 'auto'; // Default options this.options = { autoplay: false, muted: true, loop: false, preload: 'metadata', qualities: ['auto', '1080p', '720p', '480p'], theme: 'dark', ...options }; this.init(); } init() { this.createContainer(); this.createControls(); this.setupEventListeners(); this.optimizeVideo(); console.log('✅ Enhanced Video Player initialized'); } createContaer() { // Wrap video in custom container this.container = document.createElement('div'); this.container.className = 'enhanced-video-player'; // Insert container before video this.video.parentNode.insertBefore(this.container, this.video); this.container.appendChild(this.video); // Add player styles this.addPlayerStyles(); } createControls() { this.controls = document.createElement('div'); this.controls.className = 'video-controls'; this.controls.innerHTML = `
`; this.container.appendChild(this.controls); // Get control elements this.playPauseBtn = this.controls.querySelector('.play-pause-btn'); this.volumeBtn = this.controls.querySelector('.volume-btn'); this.volumeSlider = this.controls.querySelector('.volume-slider'); this.progressBar = this.controls.querySelector('.video-progress-bar'); this.progressFilled = this.controls.querySelector('.video-progress-filled'); this.progressHandle = this.controls.querySelector('.video-progress-handle'); this.currentTimeDisplay = this.controls.querySelector('.current-time'); this.durationDisplay = this.controls.querySelector('.duration'); this.qualityBtn = this.controls.querySelector('.quality-btn'); this.fullscreenBtn = this.controls.querySelector('.fullscreen-btn'); this.videoTitle = this.controls.querySelector('.video-title'); } setupEventListeners() { // Video events - Enhanced with better seeking support this.video.addEventListener('loadedmetadata', () => { console.log('🎬 Metadata loaded, duration:', this.video.duration); this.updateDuration(); }); this.video.addEventListener('durationchange', () => { console.log('🎬 Duration changed:', this.video.duration); this.updateDuration(); }); this.video.addEventListener('timeupdate', () => this.updateProgress()); this.video.addEventListener('seeked', () => { console.log('🎬 Seek completed, current time:', this.video.currentTime); this.updateProgress(); }); this.video.addEventListener('seeking', () => { console.log('🎬 Seeking to:', this.video.currentTime); }); this.video.addEventListener('ended', () => this.onVideoEnded()); this.video.addEventListener('play', () => this.onPlay()); this.video.addEventListener('pause', () => this.onPause()); this.video.addEventListener('volumechange', () => this.updateVolumeDisplay()); this.video.addEventListener('waiting', () => this.showBuffering()); this.video.addEventListener('canplay', () => this.hideBuffering()); this.video.addEventListener('loadstart', () => { console.log('🎬 Video loading started'); }); this.video.addEventListener('error', (e) => { console.error('🎬 Video error:', e); }); // Control events this.playPauseBtn.addEventListener('click', () => this.togglePlayPause()); this.volumeBtn.addEventListener('click', () => this.toggleMute()); this.volumeSlider.addEventListener('input', (e) => this.setVolume(e.target.value / 100)); this.fullscreenBtn.addEventListener('click', () => this.toggleFullscreen()); this.qualityBtn.addEventListener('click', () => this.showQualityMenu()); // Progress bar events - Enhanced seeking this.progressBar.addEventListener('mousedown', (e) => { e.preventDefault(); this.startSeeking(e); }); this.progressBar.addEventListener('click', (e) => { e.preventDefault(); // Direct click seeking if (!this.isDragging) { this.startSeeking(e); this.stopSeeking(); } }); this.progressBar.addEventListener('mousemove', (e) => this.updateSeekPreview(e)); this.progressBar.addEventListener('mouseleave', () => this.hideSeekPreview()); // Global events for seeking document.addEventListener('mousemove', (e) => this.handleSeeking(e)); document.addEventListener('mouseup', () => this.stopSeeking()); // Container events this.container.addEventListener('mouseenter', () => this.showControls()); this.container.addEventListener('mouseleave', () => this.hideControls()); this.container.addEventListener('click', (e) => { // Allow clicking anywhere in the video area to play/pause if (e.target === this.video || e.target === this.container || e.target.closest('.video-controls-overlay') === null) { this.togglePlayPause(); } }); // Keyboard shortcuts this.container.addEventListener('keydown', (e) => this.handleKeyboard(e)); this.container.setAttribute('tabindex', '0'); // Fullscreen change events document.addEventListener('fullscreenchange', () => this.handleFullscreenChange()); document.addEventListener('webkitfullscreenchange', () => this.handleFullscreenChange()); document.addEventListener('mozfullscreenchange', () => this.handleFullscreenChange()); document.addEventListener('MSFullscreenChange', () => this.handleFullscreenChange()); } optimizeVideo() { // Set optimal video attributes for quality and performance this.video.setAttribute('preload', this.options.preload); this.video.setAttribute('playsinline', 'true'); this.video.setAttribute('webkit-playsinline', 'true'); // Enhanced video quality attributes this.video.setAttribute('crossorigin', 'anonymous'); this.video.style.objectFit = 'contain'; // Optimize for different devices if (this.isMobile()) { this.video.setAttribute('muted', 'true'); this.video.setAttribute('autoplay', 'false'); } // Set initial volume this.video.volume = this.options.muted ? 0 : 0.8; // Default to 80% volume this.video.muted = this.options.muted; // Remove default controls this.video.removeAttribute('controls'); // Force load video metadata this.video.load(); console.log('🎬 Video optimized for enhanced playback'); } addPlayerStyles() { if (document.getElementById('enhanced-video-player-styles')) return; const styles = document.createElement('style'); styles.id = 'enhanced-video-player-styles'; styles.textContent = ` .enhanced-video-player { position: relative; width: 100%; background: #000; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); border: 1px solid rgba(255, 255, 255, 0.1); } .enhanced-video-player video { width: 100%; height: auto; display: block; outline: none; } .video-controls { position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); color: white; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; } .enhanced-video-player:hover .video-controls, .enhanced-video-player.show-controls .video-controls { opacity: 1; pointer-events: all; } .video-controls-overlay { padding: 20px; } .video-progress-container { margin-bottom: 15px; } .video-progress-bar { position: relative; height: 6px; background: rgba(255, 255, 255, 0.3); border-radius: 3px; cursor: pointer; margin-bottom: 8px; } .video-progress-filled { height: 100%; background: linear-gradient(90deg, #4a90e2, #74b9ff); border-radius: 3px; width: 0%; transition: width 0.1s ease; position: relative; } .video-progress-handle { position: absolute; top: 50%; right: -8px; transform: translateY(-50%); width: 16px; height: 16px; background: #4a90e2; border: 2px solid white; border-radius: 50%; cursor: pointer; opacity: 0; transition: opacity 0.3s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); } .video-progress-bar:hover .video-progress-handle { opacity: 1; } .video-time-display { display: flex; justify-content: space-between; font-size: 12px; color: rgba(255, 255, 255, 0.8); font-family: 'Courier New', monospace; } .video-controls-bottom { display: flex; align-items: center; justify-content: space-between; } .video-controls-left, .video-controls-right { display: flex; align-items: center; gap: 10px; } .video-controls-center { flex: 1; text-align: center; } .video-title { font-size: 14px; font-weight: 600; color: white; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } .video-btn { background: none; border: none; color: white; cursor: pointer; padding: 8px; border-radius: 6px; transition: all 0.3s ease; display: flex; align-items: center; gap: 6px; font-size: 14px; } .video-btn:hover { background: rgba(255, 255, 255, 0.2); transform: scale(1.05); } .video-btn i { font-size: 16px; } .volume-slider-container { position: relative; width: 80px; opacity: 0; transform: scaleX(0); transform-origin: left; transition: all 0.3s ease; } .video-controls-left:hover .volume-slider-container { opacity: 1; transform: scaleX(1); } .volume-slider { width: 100%; height: 4px; background: rgba(255, 255, 255, 0.3); border-radius: 2px; outline: none; cursor: pointer; -webkit-appearance: none; } .volume-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; background: #4a90e2; border-radius: 50%; cursor: pointer; border: 2px solid white; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } .volume-slider::-moz-range-thumb { width: 12px; height: 12px; background: #4a90e2; border-radius: 50%; cursor: pointer; border: 2px solid white; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } .quality-text { font-size: 12px; font-weight: 600; } .buffering-indicator { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 24px; z-index: 10; } .buffering-indicator i { animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .seek-preview { position: absolute; bottom: 100%; left: 0; background: rgba(0, 0, 0, 0.9); color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-family: 'Courier New', monospace; transform: translateX(-50%); margin-bottom: 8px; opacity: 0; transition: opacity 0.2s ease; pointer-events: none; white-space: nowrap; } .seek-preview.show { opacity: 1; } .quality-menu { position: absolute; bottom: 100%; right: 0; background: rgba(0, 0, 0, 0.95); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 8px; padding: 8px 0; margin-bottom: 10px; min-width: 120px; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; pointer-events: none; backdrop-filter: blur(10px); } .quality-menu.show { opacity: 1; transform: translateY(0); pointer-events: all; } .quality-option { padding: 8px 16px; cursor: pointer; transition: background 0.2s ease; font-size: 14px; color: white; } .quality-option:hover { background: rgba(74, 144, 226, 0.3); } .quality-option.active { background: rgba(74, 144, 226, 0.5); color: #4a90e2; } /* Mobile optimizations */ @media (max-width: 768px) { .video-controls-overlay { padding: 15px; } .video-controls-center { display: none; } .video-btn { padding: 12px; } .video-btn i { font-size: 18px; } .volume-slider-container { display: none; } .video-progress-bar { height: 8px; } .video-progress-handle { width: 20px; height: 20px; right: -10px; } } /* Fullscreen styles */ .enhanced-video-player.fullscreen { position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; z-index: 999999 !important; border-radius: 0 !important; background: #000 !important; margin: 0 !important; padding: 0 !important; border: none !important; box-shadow: none !important; transform: none !important; } .enhanced-video-player.fullscreen video { position: absolute !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; object-fit: contain !important; background: #000 !important; z-index: 999998 !important; transform: none !important; margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; max-width: none !important; max-height: none !important; } .enhanced-video-player.fullscreen .video-controls { position: fixed !important; bottom: 0 !important; left: 0 !important; right: 0 !important; width: 100vw !important; z-index: 1000000 !important; background: linear-gradient(transparent, rgba(0, 0, 0, 0.9)) !important; margin: 0 !important; padding: 0 !important; } .enhanced-video-player.fullscreen .video-progress-bar { height: 8px !important; cursor: pointer !important; z-index: 1000001 !important; position: relative !important; } .enhanced-video-player.fullscreen .video-progress-handle { width: 20px !important; height: 20px !important; right: -10px !important; z-index: 1000002 !important; } .enhanced-video-player.fullscreen .video-controls-overlay { padding: 25px !important; } .enhanced-video-player.fullscreen .video-btn { padding: 12px !important; font-size: 16px !important; } .enhanced-video-player.fullscreen .video-btn i { font-size: 20px !important; } /* Ensure fullscreen covers everything */ body.fullscreen-active { overflow: hidden !important; } .enhanced-video-player.fullscreen::before { content: ''; position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; background: #000 !important; z-index: 999997 !important; } `; document.head.appendChild(styles); } // Control methods togglePlayPause() { if (this.video.paused) { this.play(); } else { this.pause(); } } play() { // Ensure video is ready before playing if (this.video.readyState >= 2) { // HAVE_CURRENT_DATA const playPromise = this.video.play(); if (playPromise !== undefined) { playPromise.then(() => { console.log('✅ Video playing successfully'); }).catch(error => { console.warn('❌ Video play failed:', error); // Try to load and play again this.video.load(); setTimeout(() => { this.video.play().catch(e => console.warn('Retry play failed:', e)); }, 500); }); } } else { // Wait for video to be ready this.video.addEventListener('canplay', () => { this.play(); }, { once: true }); // Force load if not loading if (this.video.readyState === 0) { this.video.load(); } } } pause() { this.video.pause(); } toggleMute() { this.video.muted = !this.video.muted; this.updateVolumeDisplay(); } setVolume(volume) { this.video.volume = Math.max(0, Math.min(1, volume)); this.video.muted = volume === 0; this.updateVolumeDisplay(); } toggleFullscreen() { if (!document.fullscreenElement) { this.enterFullscreen(); } else { this.exitFullscreen(); } } enterFullscreen() { // Add body class to prevent scrolling and ensure proper fullscreen document.body.classList.add('fullscreen-active'); const element = this.container; if (element.requestFullscreen) { element.requestFullscreen().catch(err => { console.warn('Failed to enter fullscreen:', err); // Fallback to manual fullscreen this.container.classList.add('fullscreen'); this.fullscreenBtn.innerHTML = ''; }); } else if (element.webkitRequestFullscreen) { element.webkitRequestFullscreen(); } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if (element.msRequestFullscreen) { element.msRequestFullscreen(); } else { // Fallback for browsers that don't support fullscreen API this.container.classList.add('fullscreen'); this.fullscreenBtn.innerHTML = ''; console.log('🎬 Using fallback fullscreen mode'); } } exitFullscreen() { // Remove body class document.body.classList.remove('fullscreen-active'); if (document.exitFullscreen) { document.exitFullscreen().catch(err => { console.warn('Failed to exit fullscreen:', err); // Fallback to manual exit this.container.classList.remove('fullscreen'); this.fullscreenBtn.innerHTML = ''; }); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } else { // Fallback for browsers that don't support fullscreen API this.container.classList.remove('fullscreen'); this.fullscreenBtn.innerHTML = ''; console.log('🎬 Using fallback exit fullscreen mode'); } } // Seeking functionality startSeeking(e) { e.preventDefault(); this.isDragging = true; console.log('🎬 Start seeking - ReadyState:', this.video.readyState, 'Duration:', this.video.duration); // Ensure video metadata is loaded before seeking if (this.video.readyState >= 1 && this.video.duration > 0) { // HAVE_METADATA this.updateSeek(e); } else { console.log('🎬 Waiting for video metadata...'); // Force load metadata if not ready if (this.video.readyState === 0) { this.video.load(); } // Wait for metadata to load const onMetadataLoaded = () => { console.log('🎬 Metadata loaded, duration:', this.video.duration); this.updateSeek(e); }; this.video.addEventListener('loadedmetadata', onMetadataLoaded, { once: true }); this.video.addEventListener('durationchange', onMetadataLoaded, { once: true }); } this.container.classList.add('seeking'); } handleSeeking(e) { if (!this.isDragging) return; this.updateSeek(e); } stopSeeking() { if (!this.isDragging) return; this.isDragging = false; this.container.classList.remove('seeking'); this.hideSeekPreview(); } updateSeek(e) { const rect = this.progressBar.getBoundingClientRect(); const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)); if (this.isDragging) { // Wait for video to be ready and have valid duration if (this.video.readyState >= 1 && this.video.duration && !isNaN(this.video.duration) && isFinite(this.video.duration) && this.video.duration > 0) { const newTime = Math.max(0, Math.min(this.video.duration, percent * this.video.duration)); if (!isNaN(newTime) && isFinite(newTime)) { console.log(`🎬 Seeking to: ${newTime.toFixed(2)}s (${(percent * 100).toFixed(1)}%)`); try { this.video.currentTime = newTime; // Auto-play when user clicks on timebar if (this.video.paused) { this.play(); } } catch (error) { console.error('❌ Seeking failed:', error); } } else { console.warn('❌ Invalid seek time:', newTime); } } else { console.warn('❌ Video not ready for seeking. ReadyState:', this.video.readyState, 'Duration:', this.video.duration); } } this.updateSeekPreview(e, percent); } updateSeekPreview(e, percent = null) { if (!this.seekPreview) { this.seekPreview = document.createElement('div'); this.seekPreview.className = 'seek-preview'; this.progressBar.appendChild(this.seekPreview); } const rect = this.progressBar.getBoundingClientRect(); const actualPercent = percent !== null ? percent : Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)); // Only show preview if video duration is valid if (this.video.duration && !isNaN(this.video.duration) && isFinite(this.video.duration)) { const previewTime = actualPercent * this.video.duration; this.seekPreview.textContent = this.formatTime(previewTime); this.seekPreview.style.left = `${actualPercent * 100}%`; this.seekPreview.classList.add('show'); } } hideSeekPreview() { if (this.seekPreview) { this.seekPreview.classList.remove('show'); } } // Update methods updateProgress() { if (this.isDragging) return; // Only update progress if duration is valid if (this.video.duration && !isNaN(this.video.duration) && isFinite(this.video.duration) && this.video.duration > 0) { const percent = Math.max(0, Math.min(100, (this.video.currentTime / this.video.duration) * 100)); this.progressFilled.style.width = `${percent}%`; // Update handle position if (this.progressHandle) { this.progressHandle.style.left = `${percent}%`; } } // Always update time display this.currentTimeDisplay.textContent = this.formatTime(this.video.currentTime || 0); } updateDuration() { if (this.video.duration && !isNaN(this.video.duration) && isFinite(this.video.duration) && this.video.duration > 0) { this.durationDisplay.textContent = this.formatTime(this.video.duration); console.log('🎬 Duration updated:', this.video.duration); } else { this.durationDisplay.textContent = '0:00'; } } updateVolumeDisplay() { const volume = this.video.muted ? 0 : this.video.volume; this.volumeSlider.value = volume * 100; let icon = 'fa-volume-up'; if (this.video.muted || volume === 0) { icon = 'fa-volume-mute'; } else if (volume < 0.5) { icon = 'fa-volume-down'; } this.volumeBtn.innerHTML = ``; } // Event handlers onPlay() { this.isPlaying = true; this.playPauseBtn.innerHTML = ''; this.hideControls(); } onPause() { this.isPlaying = false; this.playPauseBtn.innerHTML = ''; this.showControls(); } onVideoEnded() { this.isPlaying = false; this.playPauseBtn.innerHTML = ''; this.showControls(); } showControls() { this.container.classList.add('show-controls'); this.clearControlsTimeout(); } hideControls() { if (!this.isPlaying) return; this.controlsTimeout = setTimeout(() => { this.container.classList.remove('show-controls'); }, 3000); } clearControlsTimeout() { if (this.controlsTimeout) { clearTimeout(this.controlsTimeout); this.controlsTimeout = null; } } showBuffering() { if (!this.bufferingIndicator) { this.bufferingIndicator = document.createElement('div'); this.bufferingIndicator.className = 'buffering-indicator'; this.bufferingIndicator.innerHTML = ''; this.container.appendChild(this.bufferingIndicator); } } hideBuffering() { if (this.bufferingIndicator) { this.bufferingIndicator.remove(); this.bufferingIndicator = null; } } showQualityMenu() { if (!this.qualityMenu) { this.qualityMenu = document.createElement('div'); this.qualityMenu.className = 'quality-menu'; this.options.qualities.forEach(quality => { const option = document.createElement('div'); option.className = 'quality-option'; option.textContent = quality; option.addEventListener('click', () => this.setQuality(quality)); this.qualityMenu.appendChild(option); }); this.qualityBtn.appendChild(this.qualityMenu); } this.qualityMenu.classList.toggle('show'); this.updateQualityMenu(); } setQuality(quality) { this.currentQuality = quality; this.qualityBtn.querySelector('.quality-text').textContent = quality; this.updateQualityMenu(); this.qualityMenu.classList.remove('show'); // Here you would implement actual quality switching console.log(`🎬 Quality changed to: ${quality}`); } updateQualityMenu() { if (!this.qualityMenu) return; this.qualityMenu.querySelectorAll('.quality-option').forEach(option => { option.classList.toggle('active', option.textContent === this.currentQuality); }); } // Keyboard shortcuts handleKeyboard(e) { switch (e.code) { case 'Space': e.preventDefault(); this.togglePlayPause(); break; case 'ArrowLeft': e.preventDefault(); this.video.currentTime = Math.max(0, this.video.currentTime - 10); break; case 'ArrowRight': e.preventDefault(); this.video.currentTime = Math.min(this.video.duration, this.video.currentTime + 10); break; case 'ArrowUp': e.preventDefault(); this.setVolume(Math.min(1, this.video.volume + 0.1)); break; case 'ArrowDown': e.preventDefault(); this.setVolume(Math.max(0, this.video.volume - 0.1)); break; case 'KeyM': e.preventDefault(); this.toggleMute(); break; case 'KeyF': case 'F11': e.preventDefault(); this.toggleFullscreen(); break; } } // Handle fullscreen state changes handleFullscreenChange() { const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement); if (isFullscreen) { this.container.classList.add('fullscreen'); document.body.classList.add('fullscreen-active'); this.fullscreenBtn.innerHTML = ''; console.log('🎬 Entered fullscreen mode'); } else { this.container.classList.remove('fullscreen'); document.body.classList.remove('fullscreen-active'); this.fullscreenBtn.innerHTML = ''; console.log('🎬 Exited fullscreen mode'); } // Ensure controls work properly in fullscreen this.showControls(); setTimeout(() => { if (this.isPlaying) { this.hideControls(); } }, 3000); } // Utility methods formatTime(seconds) { if (isNaN(seconds)) return '0:00'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); if (hours > 0) { return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } else { return `${minutes}:${secs.toString().padStart(2, '0')}`; } } isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); } setTitle(title) { this.videoTitle.textContent = title; } // Public API methods destroy() { this.clearControlsTimeout(); this.container.removeEventListener('keydown', this.handleKeyboard); document.removeEventListener('mousemove', this.handleSeeking); document.removeEventListener('mouseup', this.stopSeeking); // Restore original video this.video.setAttribute('controls', 'true'); this.container.parentNode.insertBefore(this.video, this.container); this.container.remove(); console.log('🎬 Enhanced Video Player destroyed'); } } // Auto-initialize for tutorial videos document.addEventListener('DOMContentLoaded', function() { const tutorialVideo = document.getElementById('tutorialVideo'); if (tutorialVideo) { // Initialize enhanced player when video modal is shown const originalPlayTutorial = window.playTutorial; window.playTutorial = function(type) { originalPlayTutorial(type); // Wait for modal to be visible, then enhance the video setTimeout(() => { if (!tutorialVideo.enhancedPlayer) { tutorialVideo.enhancedPlayer = new EnhancedVideoPlayer(tutorialVideo, { autoplay: false, muted: false, loop: false, preload: 'metadata' }); // Set video title const title = type === 'pc' ? 'PC Tutorial' : 'Phone Tutorial'; tutorialVideo.enhancedPlayer.setTitle(title); } }, 100); }; // Clean up when modal is closed const originalCloseVideoModal = window.closeVideoModal; window.closeVideoModal = function() { if (tutorialVideo.enhancedPlayer) { tutorialVideo.enhancedPlayer.destroy(); tutorialVideo.enhancedPlayer = null; } originalCloseVideoModal(); }; } }); // Export for use in other scripts window.EnhancedVideoPlayer = EnhancedVideoPlayer;