Spaces:
Running
Running
| // Global variables | |
| let videos = []; | |
| let currentVideoId = null; | |
| let currentPage = 1; | |
| const videosPerPage = 12; | |
| let filteredVideos = []; | |
| // DOM elements | |
| const videoGrid = document.getElementById('videoGrid'); | |
| const suggestionsContainer = document.getElementById('suggestions'); | |
| const videoTitle = document.getElementById('videoTitle'); | |
| const videoDescription = document.getElementById('videoDescription'); | |
| const searchInput = document.getElementById('searchInput'); | |
| const searchBtn = document.getElementById('searchBtn'); | |
| const paginationContainer = document.getElementById('pagination'); | |
| // Initialize the app based on current page | |
| document.addEventListener('DOMContentLoaded', () => { | |
| loadVideos(); | |
| if (window.location.pathname.includes('player.html')) { | |
| initPlayer(); | |
| } else { | |
| // Setup search functionality for index page | |
| searchInput.addEventListener('input', handleSearch); | |
| searchBtn.addEventListener('click', handleSearch); | |
| } | |
| }); | |
| // Load videos from database.json | |
| async function loadVideos() { | |
| try { | |
| const response = await fetch('database.json'); | |
| videos = await response.json(); | |
| filteredVideos = [...videos]; | |
| if (window.location.pathname.includes('player.html')) { | |
| // Player page - load current video and suggestions | |
| const urlParams = new URLSearchParams(window.location.search); | |
| currentVideoId = urlParams.get('v'); | |
| if (currentVideoId) { | |
| loadVideo(currentVideoId); | |
| renderSuggestions(); | |
| } else { | |
| // Redirect to home if no video specified | |
| window.location.href = 'index.html'; | |
| } | |
| } else { | |
| // Home page - render video grid | |
| renderVideoGrid(); | |
| renderPagination(); | |
| } | |
| } catch (error) { | |
| console.error('Error loading videos:', error); | |
| alert('Failed to load video data. Please try again later.'); | |
| } | |
| } | |
| // Handle search functionality | |
| function handleSearch() { | |
| const searchTerm = searchInput.value.toLowerCase(); | |
| if (searchTerm.trim() === '') { | |
| filteredVideos = [...videos]; | |
| } else { | |
| filteredVideos = videos.filter(video => | |
| video.title.toLowerCase().includes(searchTerm) || | |
| video.description.toLowerCase().includes(searchTerm) | |
| ); | |
| } | |
| currentPage = 1; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| } | |
| // Render video grid on home page with pagination | |
| function renderVideoGrid() { | |
| if (!videoGrid) return; | |
| videoGrid.innerHTML = ''; | |
| const startIndex = (currentPage - 1) * videosPerPage; | |
| const endIndex = startIndex + videosPerPage; | |
| const videosToShow = filteredVideos.slice(startIndex, endIndex); | |
| if (videosToShow.length === 0) { | |
| videoGrid.innerHTML = '<p class="no-results">No videos found matching your search.</p>'; | |
| return; | |
| } | |
| videosToShow.forEach(video => { | |
| const videoCard = document.createElement('div'); | |
| videoCard.className = 'video-card'; | |
| videoCard.addEventListener('click', () => { | |
| window.location.href = `player.html?v=${video.id}`; | |
| }); | |
| videoCard.innerHTML = ` | |
| <div class="thumbnail"> | |
| <img src="${video.thumbnailPath}" alt="${video.title}" loading="lazy"> | |
| ${video.duration ? `<span class="duration">${video.duration}</span>` : ''} | |
| </div> | |
| <div class="video-info"> | |
| <h3>${video.title}</h3> | |
| <p>${video.description.substring(0, 100)}...</p> | |
| </div> | |
| `; | |
| videoGrid.appendChild(videoCard); | |
| }); | |
| } | |
| // Render pagination controls | |
| function renderPagination() { | |
| if (!paginationContainer) return; | |
| paginationContainer.innerHTML = ''; | |
| const totalPages = Math.ceil(filteredVideos.length / videosPerPage); | |
| if (totalPages <= 1) return; | |
| // Previous button | |
| const prevBtn = document.createElement('button'); | |
| prevBtn.className = 'page-btn'; | |
| prevBtn.textContent = 'Previous'; | |
| prevBtn.disabled = currentPage === 1; | |
| prevBtn.addEventListener('click', () => { | |
| if (currentPage > 1) { | |
| currentPage--; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| } | |
| }); | |
| paginationContainer.appendChild(prevBtn); | |
| // Page buttons | |
| const maxVisiblePages = 5; | |
| let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2)); | |
| let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); | |
| if (endPage - startPage + 1 < maxVisiblePages) { | |
| startPage = Math.max(1, endPage - maxVisiblePages + 1); | |
| } | |
| if (startPage > 1) { | |
| const firstBtn = document.createElement('button'); | |
| firstBtn.className = 'page-btn'; | |
| firstBtn.textContent = '1'; | |
| firstBtn.addEventListener('click', () => { | |
| currentPage = 1; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }); | |
| paginationContainer.appendChild(firstBtn); | |
| if (startPage > 2) { | |
| const ellipsis = document.createElement('span'); | |
| ellipsis.textContent = '...'; | |
| paginationContainer.appendChild(ellipsis); | |
| } | |
| } | |
| for (let i = startPage; i <= endPage; i++) { | |
| const pageBtn = document.createElement('button'); | |
| pageBtn.className = `page-btn ${i === currentPage ? 'active' : ''}`; | |
| pageBtn.textContent = i; | |
| pageBtn.addEventListener('click', () => { | |
| currentPage = i; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }); | |
| paginationContainer.appendChild(pageBtn); | |
| } | |
| if (endPage < totalPages) { | |
| if (endPage < totalPages - 1) { | |
| const ellipsis = document.createElement('span'); | |
| ellipsis.textContent = '...'; | |
| paginationContainer.appendChild(ellipsis); | |
| } | |
| const lastBtn = document.createElement('button'); | |
| lastBtn.className = 'page-btn'; | |
| lastBtn.textContent = totalPages; | |
| lastBtn.addEventListener('click', () => { | |
| currentPage = totalPages; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }); | |
| paginationContainer.appendChild(lastBtn); | |
| } | |
| // Next button | |
| const nextBtn = document.createElement('button'); | |
| nextBtn.className = 'page-btn'; | |
| nextBtn.textContent = 'Next'; | |
| nextBtn.disabled = currentPage === totalPages; | |
| nextBtn.addEventListener('click', () => { | |
| if (currentPage < totalPages) { | |
| currentPage++; | |
| renderVideoGrid(); | |
| renderPagination(); | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| } | |
| }); | |
| paginationContainer.appendChild(nextBtn); | |
| } | |
| // Load a specific video on player page | |
| function loadVideo(videoId) { | |
| const video = videos.find(v => v.id === videoId); | |
| if (!video) { | |
| alert('Video not found'); | |
| window.location.href = 'index.html'; | |
| return; | |
| } | |
| currentVideoId = videoId; | |
| videoTitle.textContent = video.title; | |
| videoDescription.textContent = video.description; | |
| // Update page title | |
| document.title = `${video.title} - Video Browser`; | |
| // Initialize Video.js player | |
| const player = videojs('mainVideo', { | |
| controls: true, | |
| autoplay: false, | |
| preload: 'auto', | |
| responsive: true, | |
| fluid: true, | |
| sources: [{ | |
| src: video.videoPath, | |
| type: 'video/mp4' // Adjust based on your video format | |
| }] | |
| }); | |
| // Add subtitle tracks if available | |
| if (video.subtitleTracks) { | |
| video.subtitleTracks.forEach(track => { | |
| player.addRemoteTextTrack({ | |
| kind: 'subtitles', | |
| src: track.path, | |
| srclang: track.srclang, | |
| label: track.label, | |
| default: track.srclang === 'en' // Default to English if available | |
| }, false); | |
| }); | |
| } | |
| // Handle player errors | |
| player.on('error', () => { | |
| const errorDisplay = player.errorDisplay; | |
| errorDisplay.contentEl().innerHTML = ` | |
| <div class="vjs-error-display"> | |
| <div class="vjs-modal-dialog-content"> | |
| <h1>Error loading video</h1> | |
| <p>The video format may not be supported by your browser.</p> | |
| <p>Try using a different browser or check the video file.</p> | |
| </div> | |
| </div> | |
| `; | |
| errorDisplay.show(); | |
| }); | |
| } | |
| // Render suggested videos | |
| function renderSuggestions() { | |
| if (!suggestionsContainer) return; | |
| // Filter out current video | |
| const suggestedVideos = videos.filter(v => v.id !== currentVideoId); | |
| suggestionsContainer.innerHTML = '<h2>Suggested Videos</h2>'; | |
| suggestedVideos.forEach(video => { | |
| const suggestionCard = document.createElement('div'); | |
| suggestionCard.className = 'suggestion-card'; | |
| suggestionCard.addEventListener('click', () => { | |
| // Update URL without reloading the page | |
| window.history.pushState({}, '', `player.html?v=${video.id}`); | |
| loadVideo(video.id); | |
| renderSuggestions(); | |
| }); | |
| suggestionCard.innerHTML = ` | |
| <div class="suggestion-thumbnail"> | |
| <img src="${video.thumbnailPath}" alt="${video.title}" loading="lazy"> | |
| </div> | |
| <div class="suggestion-info"> | |
| <h3>${video.title}</h3> | |
| ${video.duration ? `<p>${video.duration}</p>` : ''} | |
| </div> | |
| `; | |
| suggestionsContainer.appendChild(suggestionCard); | |
| }); | |
| } | |
| // Initialize video player (Video.js handles most of this now) | |
| function initPlayer() { | |
| // Video.js is initialized in loadVideo function | |
| } |