| |
| const API_BASE = ''; |
|
|
| |
| const videoForm = document.getElementById('videoForm'); |
| const scenesContainer = document.getElementById('scenesContainer'); |
| const addSceneBtn = document.getElementById('addScene'); |
| const statusDiv = document.getElementById('status'); |
| const videosListDiv = document.getElementById('videosList'); |
|
|
| let sceneCount = 1; |
|
|
| |
| addSceneBtn.addEventListener('click', () => { |
| sceneCount++; |
| const sceneDiv = document.createElement('div'); |
| sceneDiv.className = 'scene'; |
| sceneDiv.innerHTML = ` |
| <div class="form-group"> |
| <label>Scene ${sceneCount} - Text to Narrate</label> |
| <textarea class="scene-text input" rows="3" placeholder="Enter the narration text..." required></textarea> |
| </div> |
| <div class="form-group"> |
| <label>Search Keywords (comma separated)</label> |
| <input type="text" class="scene-keywords input" placeholder="nature, forest, trees" required> |
| </div> |
| `; |
| scenesContainer.appendChild(sceneDiv); |
| }); |
|
|
| |
| videoForm.addEventListener('submit', async (e) => { |
| e.preventDefault(); |
| |
| |
| const scenes = Array.from(document.querySelectorAll('.scene')).map(scene => { |
| const text = scene.querySelector('.scene-text').value; |
| const keywords = scene.querySelector('.scene-keywords').value; |
| return { |
| text, |
| searchTerms: keywords.split(',').map(k => k.trim()).filter(k => k) |
| }; |
| }); |
| |
| |
| const config = { |
| orientation: document.getElementById('orientation').value, |
| voice: document.getElementById('voice').value, |
| music: document.getElementById('music').value || null, |
| musicVolume: document.getElementById('musicVolume').value, |
| captionPosition: document.getElementById('captionPosition').value, |
| paddingBack: 0 |
| }; |
| |
| |
| showStatus('Creating video... This may take a few minutes.', 'processing'); |
| |
| try { |
| const response = await fetch(`${API_BASE}/api/short-video`, { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json' |
| }, |
| body: JSON.stringify({ scenes, config }) |
| }); |
| |
| if (!response.ok) { |
| throw new Error('Failed to create video'); |
| } |
| |
| const data = await response.json(); |
| const videoId = data.videoId; |
| |
| showStatus(`Video queued! ID: ${videoId}`, 'success'); |
| |
| |
| pollVideoStatus(videoId); |
| |
| |
| setTimeout(loadVideos, 1000); |
| |
| } catch (error) { |
| showStatus(`Error: ${error.message}`, 'error'); |
| } |
| }); |
|
|
| |
| async function pollVideoStatus(videoId) { |
| const maxAttempts = 120; |
| let attempts = 0; |
| |
| const interval = setInterval(async () => { |
| attempts++; |
| |
| if (attempts > maxAttempts) { |
| clearInterval(interval); |
| showStatus('Video processing timeout', 'error'); |
| return; |
| } |
| |
| try { |
| const response = await fetch(`${API_BASE}/api/short-video/${videoId}/status`); |
| const data = await response.json(); |
| |
| if (data.status === 'ready') { |
| clearInterval(interval); |
| showStatus('Video ready! Check your videos list below.', 'success'); |
| loadVideos(); |
| } else if (data.status === 'failed') { |
| clearInterval(interval); |
| showStatus('Video processing failed', 'error'); |
| loadVideos(); |
| } |
| } catch (error) { |
| console.error('Error polling status:', error); |
| } |
| }, 5000); |
| } |
|
|
| |
| function showStatus(message, type) { |
| statusDiv.textContent = message; |
| statusDiv.className = `status ${type}`; |
| statusDiv.classList.remove('hidden'); |
| } |
|
|
| |
| async function loadVideos() { |
| try { |
| const response = await fetch(`${API_BASE}/api/short-videos`); |
| const data = await response.json(); |
| |
| if (data.videos.length === 0) { |
| videosListDiv.innerHTML = '<p class="loading">No videos yet. Create one above!</p>'; |
| return; |
| } |
| |
| videosListDiv.innerHTML = data.videos.map(video => ` |
| <div class="video-card"> |
| <h3>Video ID: ${video.id}</h3> |
| <span class="video-status ${video.status}">${video.status.toUpperCase()}</span> |
| <div class="video-actions"> |
| ${video.status === 'ready' ? ` |
| <a href="${API_BASE}/api/short-video/${video.id}" download class="btn btn-primary">Download</a> |
| ` : ''} |
| <button onclick="deleteVideo('${video.id}')" class="btn btn-secondary">Delete</button> |
| </div> |
| </div> |
| `).join(''); |
| |
| } catch (error) { |
| console.error('Error loading videos:', error); |
| videosListDiv.innerHTML = '<p class="loading">Error loading videos</p>'; |
| } |
| } |
|
|
| |
| async function deleteVideo(videoId) { |
| if (!confirm('Are you sure you want to delete this video?')) { |
| return; |
| } |
| |
| try { |
| await fetch(`${API_BASE}/api/short-video/${videoId}`, { |
| method: 'DELETE' |
| }); |
| loadVideos(); |
| } catch (error) { |
| alert('Error deleting video'); |
| } |
| } |
|
|
| |
| loadVideos(); |
|
|
| |
| setInterval(loadVideos, 10000); |
|
|