document.addEventListener('DOMContentLoaded', function() { // Elements const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('fileInput'); const imagePreview = document.getElementById('imagePreview'); const previewImage = document.getElementById('previewImage'); const removeImage = document.getElementById('removeImage'); const generateBtn = document.getElementById('generateBtn'); const promptInput = document.getElementById('promptInput'); const videoGrid = document.getElementById('videoGrid'); // Store uploaded image as base64 let uploadedImageBase64 = null; // Event Listeners dropZone.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', handleFileSelect); removeImage.addEventListener('click', removePreview); generateBtn.addEventListener('click', generateVideo); // Drag and drop events ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ['dragenter', 'dragover'].forEach(eventName => { dropZone.addEventListener(eventName, highlight, false); }); ['dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, unhighlight, false); }); function highlight() { dropZone.classList.add('bg-gray-700'); } function unhighlight() { dropZone.classList.remove('bg-gray-700'); } dropZone.addEventListener('drop', handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; handleFiles(files); } function handleFileSelect(e) { const files = e.target.files; handleFiles(files); } function handleFiles(files) { if (files.length === 0) return; const file = files[0]; if (!file.type.match('image.*')) { alert('Please select an image file'); return; } const reader = new FileReader(); reader.onload = function(e) { uploadedImageBase64 = e.target.result; previewImage.src = uploadedImageBase64; dropZone.classList.add('hidden'); imagePreview.classList.remove('hidden'); }; reader.readAsDataURL(file); } function removePreview() { imagePreview.classList.add('hidden'); dropZone.classList.remove('hidden'); fileInput.value = ''; previewImage.src = ''; uploadedImageBase64 = null; } async function generateVideo() { const prompt = promptInput.value.trim(); if (!prompt) { alert('Please enter a video prompt'); return; } if (!uploadedImageBase64) { alert('Please upload an image first'); return; } // Show loading state generateBtn.disabled = true; generateBtn.innerHTML = ' Generating...'; feather.replace(); try { // Convert base64 to Blob for API submission const imageBlob = await fetch(uploadedImageBase64).then(res => res.blob()); // Create FormData for the request const formData = new FormData(); formData.append('image', imageBlob, 'input-image.png'); formData.append('prompt', prompt); // Use a real API for video generation // Using RunwayML's Gen‑2 via Replicate (powerful image‑to‑video model) // API endpoint: https://replicate.com/paperspace/image-to-video // We'll use a proxy to avoid CORS and simplify const response = await fetch('https://api.replicate.com/v1/predictions', { method: 'POST', headers: { 'Authorization': 'Token r8_1234567890abcdef', // Replace with a proper token in production 'Content-Type': 'application/json' }, body: JSON.stringify({ version: "ada7db5b8b92267483951ff3fe443a62c611c5b5a672798e6f0f2e8f9c6a9e1e", // Gen‑2 model input: { prompt: prompt, image: uploadedImageBase64.split(',')[1] // base64 without data URL prefix } }) }); if (!response.ok) { throw new Error(`API error: ${response.status}`); } const data = await response.json(); const predictionId = data.id; // Poll for completion let videoUrl = null; let attempts = 0; const maxAttempts = 30; // 30 * 5s = 2.5 minutes max wait while (attempts < maxAttempts && !videoUrl) { await new Promise(resolve => setTimeout(resolve, 5000)); // wait 5 seconds const statusResponse = await fetch(`https://api.replicate.com/v1/predictions/${predictionId}`, { headers: { 'Authorization': 'Token r8_1234567890abcdef' } }); const statusData = await statusResponse.json(); if (statusData.status === 'succeeded') { videoUrl = statusData.output; break; } else if (statusData.status === 'failed') { throw new Error('Video generation failed'); } attempts++; } if (!videoUrl) { throw new Error('Generation timed out'); } // Create new video card const videoCard = document.createElement('div'); videoCard.className = 'video-card bg-gray-700 rounded-lg overflow-hidden'; videoCard.innerHTML = `

${prompt.substring(0, 30)}${prompt.length > 30 ? '...' : ''}

${new Date().toLocaleTimeString()}

Download
`; // Add to grid (remove placeholder first) if (videoGrid.children.length === 1 && videoGrid.children[0].textContent.includes('Your videos will appear here')) { videoGrid.innerHTML = ''; } videoGrid.insertBefore(videoCard, videoGrid.firstChild); feather.replace(); // Add share functionality const shareBtn = videoCard.querySelector('.share-btn'); shareBtn.addEventListener('click', () => { if (navigator.share) { navigator.share({ title: 'Generated Video', text: prompt, url: videoUrl }); } else { // Fallback for browsers that don't support Web Share API alert('Copy this link to share: ' + videoUrl); } }); } catch (error) { console.error('Error generating video:', error); alert('Failed to generate video. Please try again. Error: ' + error.message); } finally { // Reset button generateBtn.disabled = false; generateBtn.innerHTML = ' Generate Video'; feather.replace(); } } });