pahvalentines/waiting.php
DeepakasBTG 3246a51579 Merge pull request #14 from DeepakasBTG/frontend
Waiting: Gif song text updated
2026-02-02 20:50:58 +05:30

325 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<title>Pets at Home</title>
<meta name="description" content="Create a personalized love song for your pet with our fun and easy tool.">
<link rel="stylesheet" href="assets/css/style.css">
<?php include('opengraph.php'); ?>
</head>
<body>
<?php include('header.php'); ?>
<div class="container">
<div class="body-container">
<img class="jukebox-banner-mb" src="assets/images/jukebox-banner-mb.png" alt="Jukebox" />
<img class="jukebox-banner-dt" src="assets/images/jukebox-banner-dt.png" alt="Jukebox" />
<div class="title">Your Pet Love Song <br/>is on its way.</div>
<div class="sub-title">Wont take a minute...</div>
<div class="melody-record-container">
<img class="melody-record" src="./assets/images/blank-record.png"
alt="Melody Record" />
<svg class="record-text-overlay" viewBox="0 0 100 100">
<path id="arc-top" d="M 38,50 A 12,12 0 0,1 62,50" fill="transparent" />
<path id="arc-bottom" d="M 62,50 A 12,12 0 0,1 38,50" fill="transparent" />
<text class="top-text">
<textPath href="#arc-top" startOffset="50%" text-anchor="middle">Unleashed</textPath>
</text>
<text class="bottom-text">
<textPath href="#arc-bottom" startOffset="50%" text-anchor="middle">Melody</textPath>
</text>
</svg>
</div>
<!-- Audio player (hidden until streaming is ready) -->
<div id="audio-player-container" class="audio-player-container" style="display: none;">
<p class="audio-player-label">Listen while your video is being created...</p>
<audio id="audio-player" controls preload="none">
Your browser does not support the audio element.
</audio>
<p id="audio-tap-message" class="audio-tap-message" style="display: none;">Tap to play</p>
</div>
</div>
</div>
<?php include('footer.php'); ?>
<script>
(function() {
// Get session_id from URL query parameter
const urlParams = new URLSearchParams(window.location.search);
let sessionId = urlParams.get('session_id');
if (!sessionId) {
// No session_id in URL, check localStorage
try {
const submissionData = localStorage.getItem('submission_data');
if (submissionData) {
const data = JSON.parse(submissionData);
if (data.entries && data.entries.length > 0) {
// Sort entries by timestamp (newest first) and get the latest
const sortedEntries = data.entries.sort((a, b) => {
return new Date(b.timestamp) - new Date(a.timestamp);
});
const latestEntry = sortedEntries[0];
sessionId = latestEntry.session_id;
console.log(`Loading session from localStorage: ${sessionId} from ${latestEntry.timestamp}`);
}
}
} catch (error) {
console.error(`Error reading from localStorage: ${error}`);
}
// If still no session_id, redirect to home
if (!sessionId) {
window.location.href = '/';
return;
}
}
// Configuration
const API_BASE_URL = 'https://valentinesong.oliver.digital/back';
const POLL_INTERVAL = 10 * 1000; // 10 seconds
const MAX_POLL_TIME = 10 * 60 * 1000; // 10 minutes
// State
const startTime = Date.now();
let pollTimer = null;
let streamingStarted = false;
let audioPlayer = null;
function showAudioPlayer(sessionId) {
if (streamingStarted) return;
streamingStarted = true;
const container = document.getElementById('audio-player-container');
audioPlayer = document.getElementById('audio-player');
const tapMessage = document.getElementById('audio-tap-message');
if (!container || !audioPlayer) return;
// Set up event listeners before loading
audioPlayer.addEventListener('play', () => {
console.log('Audio playing');
tapMessage.style.display = 'none';
});
audioPlayer.addEventListener('error', (e) => {
console.error('Audio error:', e.target.error);
});
audioPlayer.addEventListener('stalled', () => {
console.log('Audio stalled - waiting for data');
});
audioPlayer.addEventListener('waiting', () => {
console.log('Audio waiting for data');
});
// Set the stream source and show container
audioPlayer.src = `${API_BASE_URL}/api/stream/${sessionId}`;
audioPlayer.load();
container.style.display = 'block';
// Wait for enough data before attempting autoplay
audioPlayer.addEventListener('canplay', function onCanPlay() {
audioPlayer.removeEventListener('canplay', onCanPlay);
// Attempt autoplay
const playPromise = audioPlayer.play();
if (playPromise !== undefined) {
playPromise.then(() => {
console.log('Audio autoplay started');
}).catch((error) => {
// Autoplay blocked - show tap to play message
console.log('Autoplay blocked:', error.message);
tapMessage.style.display = 'block';
// Tapping container or using native controls will both work
// The 'play' event listener above will hide the message
container.addEventListener('click', () => {
audioPlayer.play().catch(e => console.error('Play failed:', e));
}, { once: true });
});
}
}, { once: true });
// Fallback: if canplay doesn't fire within 5 seconds, show player anyway
setTimeout(() => {
if (tapMessage.style.display !== 'block' && audioPlayer.paused) {
console.log('Canplay timeout - showing tap message');
tapMessage.style.display = 'block';
}
}, 5000);
}
function fadeOutAudio(callback) {
if (!audioPlayer || audioPlayer.paused) {
callback();
return;
}
const fadeInterval = 50; // ms
const fadeDuration = 1000; // 1 second fade
const volumeStep = audioPlayer.volume / (fadeDuration / fadeInterval);
const fadeTimer = setInterval(() => {
if (audioPlayer.volume > volumeStep) {
audioPlayer.volume -= volumeStep;
} else {
audioPlayer.volume = 0;
audioPlayer.pause();
clearInterval(fadeTimer);
callback();
}
}, fadeInterval);
}
async function pollStatus() {
// Check if we've exceeded max poll time
if (Date.now() - startTime > MAX_POLL_TIME) {
clearInterval(pollTimer);
showTimeoutError();
return;
}
try {
const response = await fetch(`${API_BASE_URL}/api/submissions/${sessionId}/status`);
if (!response.ok) {
if (response.status === 404) {
// Session not found, redirect to home
window.location.href = '/';
console.log(`polling - no session found in API -> ${sessionId}`)
return;
}
console.error(`Status check failed: ${response.status}`);
return;
}
const data = await response.json();
// Check if streaming is ready and show audio player
if (data.streaming_ready && !streamingStarted) {
showAudioPlayer(sessionId);
}
if (data.status === 'success') {
// Generation complete, fade out audio and redirect to result page
clearInterval(pollTimer);
fadeOutAudio(() => {
window.location.href = `result.php?session_id=${sessionId}`;
});
} else if (data.status === 'fail') {
// Generation failed, fade out audio and redirect to result page
clearInterval(pollTimer);
fadeOutAudio(() => {
window.location.href = `result.php?session_id=${sessionId}`;
});
}
// For 'pending' or 'processing', continue polling
} catch (error) {
console.error(`Error polling status: ${error}`);
// Continue polling on network errors
}
}
function showTimeoutError() {
// Find and REMOVE the record container
const recordContainer = document.querySelector('.melody-record-container');
if (recordContainer) {
recordContainer.remove();
}
// Select the existing title elements
const bodyTitle = document.querySelector('.body-container div.title');
const bodySubTitle = document.querySelector('.body-container div.sub-title');
// Update the text
if (bodyTitle) {
bodyTitle.textContent = 'Taking longer than expected...';
}
if (bodySubTitle) {
bodySubTitle.textContent = 'Your song is still being created. Please check back in a few minutes.';
}
// Create the NEW buttons div
const newDiv = document.createElement('div');
newDiv.className = 'action-btns';
newDiv.innerHTML = `
<button class="make-another-song-btn" onclick="window.location.reload()">
Check Again
</button>
<button class="make-another-song-btn" onclick="window.location.href='/'">
Create New Song
</button>
`;
// Place buttons after the sub-title
if (bodySubTitle) {
bodySubTitle.after(newDiv);
} else if (bodyTitle) {
bodyTitle.after(newDiv);
}
}
// Start polling immediately and then every 10 seconds
pollStatus();
pollTimer = setInterval(pollStatus, POLL_INTERVAL);
})();
(function() {
const phrases = [
{ top: "Brown Eyed", bottom: "Gerbil" },
{ top: "Cat it", bottom: "Be Love" },
{ top: "How Squeaky", bottom: "is Your Love" },
{ top: "I Just Called", bottom: "To Say I Wuf You" },
{ top: "I'll Sit Stay", bottom: "And Stand By You" },
{ top: "Kiss Me", bottom: "Meow" },
{ top: "My Bark", bottom: "Will Go On" },
{ top: "Something The", bottom: "Way You Purr" },
{ top: "Unfor-Pet-able", bottom: "" },
{ top: "Unleashed", bottom: "Melody" }
];
let index = 0;
let textSwitchInterval = 10; // Seconds between switches
let intervalMs = textSwitchInterval * 1000;
let fadeMs = intervalMs * 0.06; // Relative fade timing (e.g., 600ms for 10s)
const overlay = document.querySelector('.record-text-overlay');
const topText = document.querySelector('.top-text textPath');
const bottomText = document.querySelector('.bottom-text textPath');
if (overlay && topText && bottomText) {
overlay.style.transition = `opacity ${fadeMs}ms ease-in-out`;
setInterval(() => {
overlay.classList.add('text-hidden');
setTimeout(() => {
index = (index + 1) % phrases.length;
topText.textContent = phrases[index].top;
bottomText.textContent = phrases[index].bottom;
overlay.classList.remove('text-hidden');
}, fadeMs + 100); // Wait for fade out before swap
}, intervalMs);
}
})();
</script>
</body>
</html>