class PornCinema extends BaseVideoPlayer { constructor() { super('#video-container', { showControls: true, autoHide: true, showProgress: true, showVolume: true, showFullscreen: true, showQuality: true, showSpeed: true, keyboardShortcuts: true, minimal: false }); // Cinema-specific properties this.playlist = []; this.currentPlaylistIndex = -1; this.videoLibrary = null; // Playback modes - default to loop playlist this.repeatMode = 'all'; // 'off', 'one', 'all' console.log('🎬 PornCinema extends BaseVideoPlayer'); } async initialize() { console.log('🎬 Initializing Porn Cinema...'); try { // Initialize stats tracking this.initializeStatsTracking(); // Initialize video library this.videoLibrary = new VideoLibrary(this); await this.videoLibrary.loadVideoLibrary(); // Setup playlist UI event handlers this.setupPlaylistHandlers(); // Initialize repeat button this.updateRepeatButton(); console.log('✅ Porn Cinema initialized successfully'); } catch (error) { console.error('🎬 ❌ Error initializing Porn Cinema:', error); throw error; } } selectVideo(video) { console.log('🎬 Playing video:', video.name); try { this.loadVideo(video.path, true); } catch (error) { console.error('🎬 ❌ Error playing video:', error); } } playVideo(video) { console.log('🎬 Playing video via VideoLibrary:', video.name); try { // Track video start for stats this.trackVideoStart(video); // Update video title and info if elements exist const videoTitle = document.getElementById('video-title'); const videoInfo = document.getElementById('video-info'); if (videoTitle) { videoTitle.textContent = video.name || 'Unknown Title'; } if (videoInfo) { videoInfo.textContent = `${video.category || 'Video'} • ${video.duration || 'Unknown duration'}`; } // Use BaseVideoPlayer's loadVideo method this.loadVideo(video.path, true); } catch (error) { console.error('🎬 ❌ Error playing video:', error); } } async addToPlaylist(video) { console.log('🎬 Adding to playlist:', video.name); try { // Add video to playlist if not already present if (!this.playlist.find(v => v.path === video.path)) { this.playlist.push(video); console.log(`✅ Added to playlist: ${video.name}`); // Track stats this.trackVideoAddedToPlaylist(video); // Update playlist display this.updatePlaylistDisplay(); // Show notification this.showPlaylistNotification(`Added "${video.name}" to playlist`); } else { console.log(`ℹ️ Video already in playlist: ${video.name}`); this.showPlaylistNotification(`"${video.name}" is already in playlist`); } } catch (error) { console.error('🎬 ❌ Error adding to playlist:', error); } } updatePlaylistDisplay() { const playlistContent = document.getElementById('playlist-content'); if (!playlistContent) return; if (this.playlist.length === 0) { playlistContent.innerHTML = `

Playlist is empty. Add videos by clicking ➕ or pressing Enter while a video is selected.

`; return; } playlistContent.innerHTML = `
${this.playlist.map((video, index) => this.createPlaylistItem(video, index)).join('')}
`; // Attach event listeners to playlist items this.attachPlaylistItemEvents(); } createPlaylistItem(video, index) { const isCurrentVideo = index === this.currentPlaylistIndex; const duration = this.formatDuration(video.duration || 0); const size = this.formatFileSize(video.size || 0); return `
${video.name}
${duration} • ${size}
`; } attachPlaylistItemEvents() { // Remove old event listeners by using event delegation instead of individual listeners // This prevents memory leaks from accumulating listeners const playlistContent = document.getElementById('playlist-content'); if (!playlistContent) return; // Remove old delegated listener if it exists if (this.playlistDelegateHandler) { playlistContent.removeEventListener('click', this.playlistDelegateHandler); } // Create new delegated event handler this.playlistDelegateHandler = (e) => { const playButton = e.target.closest('.btn-playlist-play'); const removeButton = e.target.closest('.btn-playlist-remove'); const playlistItem = e.target.closest('.playlist-item'); if (playButton) { e.stopPropagation(); const index = parseInt(playButton.dataset.index); this.playFromPlaylist(index); } else if (removeButton) { e.stopPropagation(); const index = parseInt(removeButton.dataset.index); this.removeFromPlaylist(index); } else if (playlistItem && !e.target.closest('.playlist-item-actions')) { const index = parseInt(playlistItem.dataset.index); this.playFromPlaylist(index); } }; // Add single delegated event listener playlistContent.addEventListener('click', this.playlistDelegateHandler); } playFromPlaylist(index) { if (index < 0 || index >= this.playlist.length) return; const video = this.playlist[index]; this.currentPlaylistIndex = index; console.log(`🎬 Playing from playlist [${index}]: ${video.name}`); this.playVideo(video); this.updatePlaylistDisplay(); // Update to show current video } removeFromPlaylist(index) { if (index < 0 || index >= this.playlist.length) return; const video = this.playlist[index]; this.playlist.splice(index, 1); // Adjust current playlist index if needed if (this.currentPlaylistIndex > index) { this.currentPlaylistIndex--; } else if (this.currentPlaylistIndex === index) { this.currentPlaylistIndex = -1; // Current video was removed } console.log(`🎬 Removed from playlist: ${video.name}`); this.updatePlaylistDisplay(); this.showPlaylistNotification(`Removed "${video.name}" from playlist`); } setupPlaylistHandlers() { // Repeat mode button const repeatBtn = document.getElementById('repeat-mode-btn'); if (repeatBtn) { repeatBtn.addEventListener('click', () => this.toggleRepeatMode()); } // Clear playlist button const clearBtn = document.getElementById('clear-playlist'); if (clearBtn) { clearBtn.addEventListener('click', () => this.clearPlaylist()); } // Shuffle playlist button const shuffleBtn = document.getElementById('shuffle-playlist'); if (shuffleBtn) { shuffleBtn.addEventListener('click', () => this.shufflePlaylist()); } // Save playlist button (placeholder for now) const saveBtn = document.getElementById('save-playlist'); if (saveBtn) { saveBtn.addEventListener('click', () => this.savePlaylist()); } // Load playlist button (placeholder for now) const loadBtn = document.getElementById('load-playlist'); if (loadBtn) { loadBtn.addEventListener('click', () => this.loadPlaylist()); } } clearPlaylist() { this.playlist = []; this.currentPlaylistIndex = -1; this.updatePlaylistDisplay(); this.showPlaylistNotification('Playlist cleared'); console.log('🎬 Playlist cleared'); } shufflePlaylist() { if (this.playlist.length < 2) { this.showPlaylistNotification('Need at least 2 videos to shuffle'); return; } // Fisher-Yates shuffle algorithm for (let i = this.playlist.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [this.playlist[i], this.playlist[j]] = [this.playlist[j], this.playlist[i]]; } this.currentPlaylistIndex = -1; // Reset current index after shuffle this.updatePlaylistDisplay(); this.showPlaylistNotification('Playlist shuffled'); console.log('🎬 Playlist shuffled'); } toggleRepeatMode() { const modes = ['off', 'one', 'all']; const currentIndex = modes.indexOf(this.repeatMode); this.repeatMode = modes[(currentIndex + 1) % modes.length]; this.updateRepeatButton(); this.showPlaylistNotification(`Repeat: ${this.getRepeatModeLabel()}`); console.log(`🎬 Repeat mode: ${this.repeatMode}`); } getRepeatModeLabel() { switch (this.repeatMode) { case 'off': return 'Off'; case 'one': return 'Current Video'; case 'all': return 'All Videos'; default: return 'Off'; } } updateRepeatButton() { const repeatBtn = document.getElementById('repeat-mode-btn'); if (repeatBtn) { let icon, title; switch (this.repeatMode) { case 'off': icon = '🔁'; title = 'Repeat: Off'; repeatBtn.style.opacity = '0.5'; break; case 'one': icon = '🔂'; title = 'Repeat: Current Video'; repeatBtn.style.opacity = '1'; break; case 'all': icon = '🔁'; title = 'Repeat: All Videos'; repeatBtn.style.opacity = '1'; break; } repeatBtn.textContent = icon; repeatBtn.title = title; } } playNextVideo() { console.log(`🎬 playNextVideo called - playlist length: ${this.playlist.length}, current index: ${this.currentPlaylistIndex}`); if (this.playlist.length === 0) { console.log('🎬 No playlist to continue'); return false; } let nextIndex = this.currentPlaylistIndex + 1; console.log(`🎬 Next index would be: ${nextIndex}, repeat mode: ${this.repeatMode}`); // Handle end of playlist if (nextIndex >= this.playlist.length) { if (this.repeatMode === 'all') { nextIndex = 0; // Loop back to start console.log('🎬 Looping back to start of playlist'); } else { console.log('🎬 End of playlist reached'); return false; } } console.log(`🎬 Playing video at index ${nextIndex}: ${this.playlist[nextIndex]?.name}`); this.playFromPlaylist(nextIndex); return true; } async savePlaylist() { if (this.playlist.length === 0) { this.showPlaylistNotification('Cannot save empty playlist'); return; } // Show save dialog to get playlist name this.showSavePlaylistDialog(); } showSavePlaylistDialog() { // Create modal dialog for saving const modal = document.createElement('div'); modal.className = 'playlist-modal'; modal.innerHTML = `

Save Playlist

${this.playlist.length} videos selected
`; // Add modal styles modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; justify-content: center; z-index: 10002; backdrop-filter: blur(5px); `; document.body.appendChild(modal); // Focus on input and select text const input = modal.querySelector('#playlist-name-input'); setTimeout(() => { input.focus(); input.select(); }, 100); // Setup event handlers this.setupSaveModalEvents(modal); } setupSaveModalEvents(modal) { const input = modal.querySelector('#playlist-name-input'); const saveBtn = modal.querySelector('.btn-save-playlist'); const saveExportBtn = modal.querySelector('.btn-save-and-export'); const closeBtn = modal.querySelector('.playlist-modal-close'); // Close modal handlers const closeModal = () => { document.body.removeChild(modal); }; closeBtn.addEventListener('click', closeModal); modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); }); // Save handlers const savePlaylist = async (shouldExport = false) => { const name = input.value.trim(); if (!name) { input.focus(); return; } try { const playlistData = { name: name, created: new Date().toISOString(), videos: this.playlist.map(video => ({ name: video.name, path: video.path, duration: video.duration, size: video.size, type: video.type })), count: this.playlist.length }; // Save to localStorage const savedPlaylists = this.getSavedPlaylists(); // Check for duplicate names const existingIndex = savedPlaylists.findIndex(p => p.name === name); if (existingIndex >= 0) { // Replace existing playlist savedPlaylists[existingIndex] = playlistData; this.showPlaylistNotification(`Updated playlist: ${name}`); } else { // Add new playlist savedPlaylists.push(playlistData); this.showPlaylistNotification(`Saved playlist: ${name}`); } localStorage.setItem('pornCinema_savedPlaylists', JSON.stringify(savedPlaylists)); // Track playlist creation stats this.trackPlaylistCreated(playlistData); // Export if requested if (shouldExport) { await this.downloadPlaylistFile(playlistData); } console.log('🎬 ✅ Playlist saved:', name); closeModal(); } catch (error) { console.error('🎬 ❌ Error saving playlist:', error); this.showPlaylistNotification('Error saving playlist'); } }; saveBtn.addEventListener('click', () => savePlaylist(false)); saveExportBtn.addEventListener('click', () => savePlaylist(true)); // Enter key to save input.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); savePlaylist(false); } }); } async loadPlaylist() { try { const savedPlaylists = this.getSavedPlaylists(); if (savedPlaylists.length === 0) { // No saved playlists, offer file upload this.showPlaylistLoadDialog(); return; } // Show playlist selection dialog this.showPlaylistSelectionDialog(savedPlaylists); } catch (error) { console.error('🎬 ❌ Error loading playlist:', error); this.showPlaylistNotification('Error loading playlist'); } } getSavedPlaylists() { try { const saved = localStorage.getItem('pornCinema_savedPlaylists'); return saved ? JSON.parse(saved) : []; } catch (error) { console.error('🎬 ❌ Error getting saved playlists:', error); return []; } } async downloadPlaylistFile(playlistData) { const dataStr = JSON.stringify(playlistData, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `${playlistData.name}.json`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } showPlaylistSelectionDialog(savedPlaylists) { // Create modal dialog const modal = document.createElement('div'); modal.className = 'playlist-modal'; modal.innerHTML = `

Load Playlist

${savedPlaylists.map((playlist, index) => `
${playlist.name}
${playlist.count} videos • ${new Date(playlist.created).toLocaleDateString()}
`).join('')}
Or load from file
`; // Add modal styles modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; justify-content: center; z-index: 10002; backdrop-filter: blur(5px); `; document.body.appendChild(modal); // Add event listeners this.setupPlaylistModalEvents(modal, savedPlaylists); } showPlaylistLoadDialog() { // Simple file upload dialog const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.style.display = 'none'; input.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { this.loadPlaylistFromFile(file); } }); document.body.appendChild(input); input.click(); document.body.removeChild(input); } setupPlaylistModalEvents(modal, savedPlaylists) { // Close modal const closeBtn = modal.querySelector('.playlist-modal-close'); closeBtn.addEventListener('click', () => { document.body.removeChild(modal); }); // Click outside to close modal.addEventListener('click', (e) => { if (e.target === modal) { document.body.removeChild(modal); } }); // Load playlist buttons const loadBtns = modal.querySelectorAll('.btn-load-playlist'); loadBtns.forEach(btn => { btn.addEventListener('click', () => { const index = parseInt(btn.dataset.index); this.loadSavedPlaylist(savedPlaylists[index]); document.body.removeChild(modal); }); }); // Export playlist buttons const exportBtns = modal.querySelectorAll('.btn-export-playlist'); exportBtns.forEach(btn => { btn.addEventListener('click', async () => { const index = parseInt(btn.dataset.index); await this.downloadPlaylistFile(savedPlaylists[index]); this.showPlaylistNotification(`Exported playlist: ${savedPlaylists[index].name}`); }); }); // Delete playlist buttons const deleteBtns = modal.querySelectorAll('.btn-delete-playlist'); deleteBtns.forEach(btn => { btn.addEventListener('click', () => { const index = parseInt(btn.dataset.index); this.deleteSavedPlaylist(index); document.body.removeChild(modal); // Refresh the dialog const updatedPlaylists = this.getSavedPlaylists(); if (updatedPlaylists.length > 0) { this.showPlaylistSelectionDialog(updatedPlaylists); } }); }); // File upload const uploadBtn = modal.querySelector('.btn-upload-playlist'); const fileInput = modal.querySelector('#playlist-file-input'); uploadBtn.addEventListener('click', () => { fileInput.click(); }); fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { this.loadPlaylistFromFile(file); document.body.removeChild(modal); } }); } loadSavedPlaylist(playlistData) { try { this.playlist = playlistData.videos || []; this.currentPlaylistIndex = -1; this.updatePlaylistDisplay(); this.showPlaylistNotification(`Loaded playlist: ${playlistData.name} (${this.playlist.length} videos)`); console.log('🎬 ✅ Playlist loaded:', playlistData.name); } catch (error) { console.error('🎬 ❌ Error loading saved playlist:', error); this.showPlaylistNotification('Error loading playlist'); } } async loadPlaylistFromFile(file) { try { const text = await file.text(); const playlistData = JSON.parse(text); // Validate playlist data if (!playlistData.videos || !Array.isArray(playlistData.videos)) { throw new Error('Invalid playlist format'); } this.loadSavedPlaylist(playlistData); } catch (error) { console.error('🎬 ❌ Error loading playlist from file:', error); this.showPlaylistNotification('Error loading playlist file'); } } deleteSavedPlaylist(index) { try { const savedPlaylists = this.getSavedPlaylists(); const deleted = savedPlaylists.splice(index, 1)[0]; localStorage.setItem('pornCinema_savedPlaylists', JSON.stringify(savedPlaylists)); this.showPlaylistNotification(`Deleted playlist: ${deleted.name}`); console.log('🎬 ✅ Playlist deleted:', deleted.name); } catch (error) { console.error('🎬 ❌ Error deleting playlist:', error); this.showPlaylistNotification('Error deleting playlist'); } } showPlaylistNotification(message) { // Create a simple notification system const notification = document.createElement('div'); notification.className = 'playlist-notification'; notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: rgba(0, 0, 0, 0.8); color: white; padding: 10px 15px; border-radius: 5px; z-index: 10001; font-size: 14px; backdrop-filter: blur(5px); border: 1px solid rgba(255, 255, 255, 0.1); `; document.body.appendChild(notification); // Remove after 3 seconds setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 3000); } formatDuration(seconds) { if (!seconds || seconds === 0) return '--:--'; 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')}`; } } formatFileSize(bytes) { if (!bytes || bytes === 0) return '--'; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${sizes[i]}`; } // ===== STATS TRACKING METHODS ===== initializeStatsTracking() { // Initialize global stats tracker if not already done if (!window.playerStats) { window.playerStats = new PlayerStats(); } this.stats = window.playerStats; console.log('📊 Stats tracking initialized for PornCinema'); } trackVideoStart(video) { if (this.stats) { this.stats.onVideoStart(video); } } trackVideoPlay() { if (this.stats) { this.stats.onVideoPlay(); } } trackVideoPause() { if (this.stats) { this.stats.onVideoPause(); } } trackVideoEnd(completionPercentage) { if (this.stats) { this.stats.onVideoEnd(completionPercentage); } } trackPlaylistCreated(playlist) { if (this.stats) { this.stats.onPlaylistCreated(playlist); } } trackVideoAddedToPlaylist(video) { if (this.stats) { this.stats.onVideoAddedToPlaylist(video); } } // ===== OVERRIDE BASEVIDEOPLAYER EVENTS FOR STATS ===== onPlay() { super.onPlay(); // Call parent method this.trackVideoPlay(); } onPause() { super.onPause(); // Call parent method this.trackVideoPause(); } onEnded() { console.log('🎬 Video ended - starting onEnded handler'); // Calculate completion percentage before calling parent let completionPercentage = 100; if (this.videoElement && this.videoElement.duration > 0) { completionPercentage = (this.videoElement.currentTime / this.videoElement.duration) * 100; } super.onEnded(); // Call parent method this.trackVideoEnd(completionPercentage); console.log(`🎬 Repeat mode: ${this.repeatMode}`); // Handle repeat and autoplay if (this.repeatMode === 'one') { // Repeat current video console.log('🎬 Repeating current video'); this.videoElement.currentTime = 0; this.play(); } else { // Try to play next video in playlist console.log('🎬 Attempting to play next video...'); if (!this.playNextVideo()) { console.log('🎬 Playback finished - no more videos'); } } } // Cleanup method to prevent memory leaks destroy() { console.log('🎬 Cleaning up Porn Cinema...'); try { // Remove delegated event handler const playlistContent = document.getElementById('playlist-content'); if (playlistContent && this.playlistDelegateHandler) { playlistContent.removeEventListener('click', this.playlistDelegateHandler); this.playlistDelegateHandler = null; } // Stop and unload video if (this.videoElement) { this.videoElement.pause(); this.videoElement.src = ''; this.videoElement.load(); } // Clear playlist this.playlist = []; this.currentPlaylistIndex = -1; // Destroy video library if it exists if (this.videoLibrary && typeof this.videoLibrary.destroy === 'function') { this.videoLibrary.destroy(); } console.log('✅ Porn Cinema cleanup complete'); } catch (error) { console.error('❌ Error during Porn Cinema cleanup:', error); } } } window.PornCinema = PornCinema;