// Index page functionality document.addEventListener('DOMContentLoaded', () => { const youtubeUrlInput = document.getElementById('youtube-url'); const processButton = document.getElementById('process-button'); const processStatus = document.getElementById('process-status'); const processingIndicator = document.getElementById('processing'); const recentlyProcessedCard = document.getElementById('recently-processed'); const videoListContainer = document.getElementById('video-list'); // Example video buttons const exampleButtons = document.querySelectorAll('.example-video'); // Process button click handler processButton.addEventListener('click', () => processVideo()); // Enter key in input field youtubeUrlInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') processVideo(); }); // Example video buttons exampleButtons.forEach(button => { button.addEventListener('click', () => { youtubeUrlInput.value = button.dataset.url; processVideo(); }); }); // Process video function function processVideo() { const youtubeUrl = youtubeUrlInput.value.trim(); if (!youtubeUrl) { processStatus.innerHTML = '
Please enter a YouTube URL
'; return; } // Extract video ID const videoId = extractVideoId(youtubeUrl); if (!videoId) { processStatus.innerHTML = '
Invalid YouTube URL
'; return; } // Show loading indicator with spinner and text processStatus.innerHTML = `
Processing video... This may take a few moments
`; // Set a timeout to handle overly long processing const timeoutId = setTimeout(() => { processStatus.innerHTML = `
Processing is taking longer than expected. Please wait...
`; }, 20000); // 20 seconds // Send request to process the video fetch('/api/video/process', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: youtubeUrl }) }) .then(response => { if (!response.ok) { throw new Error('Failed to process video'); } return response.json(); }) .then(data => { // Clear timeout for long-running process clearTimeout(timeoutId); // Extract video ID from response (handles both old and new API formats) const videoId = data.video ? data.video.video_id : data.video_id; const isNewlyProcessed = data.newly_processed !== undefined ? data.newly_processed : true; if (!videoId) { throw new Error('Invalid response: Missing video ID'); } // Get video title (for display) const videoTitle = data.video ? data.video.title : (data.title || `Video ${videoId}`); // Log for debugging console.log('Process response:', {videoId, isNewlyProcessed, data}); // Show success message processStatus.innerHTML = ` `; // Update recent videos lists displayRecentVideos(); loadFooterRecentVideos(); // Update footer videos as well }) .catch(error => { // Clear timeout for long-running process clearTimeout(timeoutId); // Show error message console.error('Process error:', error); processStatus.innerHTML = handleError(error); }); } // Display recently processed videos function displayRecentVideos() { // Show loading state recentlyProcessedCard.classList.remove('hidden'); videoListContainer.innerHTML = `
Loading recent videos...
`; const carouselPrev = document.getElementById('carousel-prev'); const carouselNext = document.getElementById('carousel-next'); // Fetch recent videos from server fetch('/api/video/recent?limit=5') .then(response => { if (!response.ok) { throw new Error('Failed to fetch recent videos'); } return response.json(); }) .then(videos => { if (videos && videos.length > 0) { // Limit to 5 videos const limitedVideos = videos.slice(0, 5); // Generate carousel items const carouselItems = limitedVideos.map((video, index) => { // Format date if available let formattedDate = ''; if (video.created_at) { const date = new Date(video.created_at * 1000); // Convert Unix timestamp to milliseconds formattedDate = date.toLocaleDateString(); } // Use title or default const videoTitle = video.title || `Video ${video.video_id}`; return ` `; }).join(''); // Add carousel items to container videoListContainer.innerHTML = carouselItems; // Setup navigation arrows if (limitedVideos.length > 1) { // Show arrows for multiple videos let currentIndex = 0; const maxIndex = limitedVideos.length - 1; // Show navigation arrows carouselPrev.classList.remove('hidden'); carouselNext.classList.remove('hidden'); // Left button is disabled by default (we're at the start) const prevButton = carouselPrev.querySelector('button'); const nextButton = carouselNext.querySelector('button'); prevButton.classList.add('btn-disabled'); // Functions to update button states const updateButtonStates = () => { if (currentIndex === 0) { prevButton.classList.add('btn-disabled'); } else { prevButton.classList.remove('btn-disabled'); } if (currentIndex === maxIndex) { nextButton.classList.add('btn-disabled'); } else { nextButton.classList.remove('btn-disabled'); } }; // Setup navigation buttons prevButton.addEventListener('click', () => { if (currentIndex > 0) { currentIndex--; document.getElementById(`video-${currentIndex}`).scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); updateButtonStates(); } }); nextButton.addEventListener('click', () => { if (currentIndex < maxIndex) { currentIndex++; document.getElementById(`video-${currentIndex}`).scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); updateButtonStates(); } }); } else { // Hide arrows for single video carouselPrev.classList.add('hidden'); carouselNext.classList.add('hidden'); } } else { recentlyProcessedCard.classList.add('hidden'); carouselPrev.classList.add('hidden'); carouselNext.classList.add('hidden'); } }) .catch(error => { console.error('Error fetching recent videos:', error); videoListContainer.innerHTML = `
Failed to load recent videos
`; carouselPrev.classList.add('hidden'); carouselNext.classList.add('hidden'); }); } // Display recent videos on page load displayRecentVideos(); });