You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
9.9 KiB
272 lines
9.9 KiB
6 months ago
|
<!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
|
||
|
let videoPath = `${formattedPath}latest.mp4`;
|
||
|
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>
|