<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Animator</title> <style> body { font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; margin: 0; padding: 20px; } iframe { width: 99%; /* Full width to use available space */ height: 500px; border: 1px solid #ccc; margin-bottom: 20px; } #current-url { font-size: 16px; color: #333; width: 100%; /* Makes sure it takes the full container width */ word-wrap: break-word; /* Ensures the text wraps in the div */ margin-bottom: 10px; /* Space before the navigation buttons */ } .button-group { display: flex; /* Aligns buttons in a row */ justify-content: center; /* Centers buttons horizontally */ gap: 10px; /* Adds space between buttons */ } button { padding: 5px 10px; margin: 10px; border-radius: 5px; /* Rounded corners */ border: 1px solid #ccc; /* Grey border */ display: inline-block; /* Ensures buttons are inline and can control additional layout properties */ font-size: 16px; } #backButton, #forwardButton { background-color: #f0f0f0; /* Light grey background */ color: #333; /* Dark text */ padding: 0px 10px; /* Reduced vertical padding for narrow height */ cursor: pointer; /* Cursor indicates button */ height: 24px; /* Fixed height for a narrower button */ line-height: 16px; /* Adjust line height to vertically center the text */ margin: 2px; /* Small margin to separate buttons slightly */ } #backButton:hover, #forwardButton:hover { background-color: #e8e8e8; /* Slightly darker background on hover */ } video { display: none; /* Initially hide the video player */ width: 99%; /* Adjust based on your layout needs, or use max-width for responsiveness */ height: auto; /* Maintain aspect ratio */ margin-top: 20px; /* Ensure it's centered properly */ max-width: 640px; /* Max width of the video */ border: 1px solid #ccc; /* Optional, adds a border for better visibility */ } </style> </head> <body> <h1>Animate a Folder of Images</h1> <p>Navigate to a folder of 60+ images.</p> <iframe id="iframe" src="{{ initial_url }}"></iframe> <div class="button-group"> <!-- Button group for inline display --> <button id="backButton" onclick="goBack()">←</button> <button id="forwardButton" onclick="goForward()">→</button> </div> <button id="submit-button" onclick="submitUrl()" style="display:none;">Create Latest Movie</button> <div id="loading-spinner" style="display: none;"> <div class="spinner"></div> </div> <style> .spinner { border: 8px solid #f3f3f3; /* Light grey */ border-top: 8px solid #3498db; /* Blue */ border-radius: 50%; width: 50px; height: 50px; animation: spin 45s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> <video id="video-player" controls loop style="display: none;"> <source id="video-source" type="video/mp4"> Your browser does not support the video tag. </video> <script> function goBack() { document.getElementById('iframe').contentWindow.history.back(); } function goForward() { document.getElementById('iframe').contentWindow.history.forward(); } // function updateUrl(url) { // document.getElementById('url').textContent = url; // } function updateUrl(url) { document.getElementById('url').textContent = url; } function handleVideoSuccess() { console.log("Video loaded successfully."); document.getElementById('video-player').style.display = 'block'; // Show the video player only if the video loads successfully } function handleVideoError() { console.log("Unable to load video."); document.getElementById('video-player').style.display = 'none'; // Hide the video player document.getElementById('submit-button').textContent = 'Generate Movie'; } function updateVideo(url) { // Convert the full URL to a format suitable for your video path let formattedPath = url.replace(/https?:\/\//, '') // Remove the protocol part .replace(/\./g, '_') // Replace dots with underscores .replace(/\//g, '-'); // Replace slashes with hyphens // Check if the formattedPath ends with a slash, if not append '-' if (!formattedPath.endsWith('-')) { formattedPath += '-'; } // Append '.mp4' to the formatted path + cache bust let videoPath = `${formattedPath}latest.mp4` + "?t=" + Date.now(); let videoPlayer = document.getElementById('video-player'); let videoSource = document.getElementById('video-source'); videoPlayer.muted = true; // Set up event listeners before setting the source videoSource.onerror = handleVideoError; // videoSource.onloadedmetadata = handleVideoSuccess; console.log("Fetched latest") videoSource.src = `/videos/${videoPath}`; videoPlayer.load(); // videoPlayer.style.display = 'block'; videoPlayer.play().then(() => { // The video is playing, show the player console.log("Video loaded and playing."); videoPlayer.style.display = 'block'; }).catch(error => { // Error playing the video console.log("Failed to play video: ", error); videoPlayer.style.display = 'none'; }); document.getElementById('submit-button').textContent = 'Generate Latest Movie'; } window.addEventListener('message', function (event) { if (event.origin === '{{ host }}') { var data = event.data; if (data && data.type === 'urlUpdate') { const submitButton = document.getElementById('submit-button'); const videoPlayer = document.getElementById('video-player'); updateUrl(data.url); if (data.eligible) { submitButton.style.display = 'block'; // Show the button updateVideo(data.url); } else { submitButton.style.display = 'none'; // Hide the button videoPlayer.style.display = 'none'; // Hide the video } const newSubpath = new URL(data.url).pathname; // Extract the path from the URL // Update the browser's URL to reflect the iframe's navigation const newPath = `/iframe${newSubpath}`; // Construct the new path document.getElementById('share-button').setAttribute('data-url', window.location.origin + newPath); // history.pushState({ path: newPath }, '', newPath); } } }); function submitUrl() { const url = document.getElementById('url').textContent; const payload = { url: url }; document.getElementById('loading-spinner').style.display = 'block'; // Show the loading spinner document.getElementById('submit-button').style.display = 'none'; // Hide the button console.log("Requesting new video.") fetch('{{ api_url }}', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).then(response => response.json()) .then(data => { console.log(data); // Hide the loading spinner document.getElementById('loading-spinner').style.display = 'none'; document.getElementById('submit-button').style.display = 'block'; updateUrl(url); // Re-attempt to load the video updateVideo(url); }) .catch(error => { console.error('Error:', error); // Hide the loading spinner document.getElementById('loading-spinner').style.display = 'none'; document.getElementById('submit-button').style.display = 'block'; }); } function copyUrlToClipboard() { const url = document.getElementById('share-button').getAttribute('data-url'); navigator.clipboard.writeText(url).then(() => { alert('URL copied to clipboard!'); }).catch(err => { console.error('Failed to copy: ', err); }); } </script> <button id="share-button" onclick="copyUrlToClipboard()">Share Link</button> <div align="center" id="current-url">Source: <span id="url">Loading...</span></div> </body> </html>