344 lines
13 KiB
HTML
344 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Viva++</title>
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
|
<style>
|
|
body {
|
|
background-color: #000;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
}
|
|
|
|
.loader {
|
|
border: 1.5vw solid #333;
|
|
border-top: 1.5vw solid #3498db;
|
|
border-bottom: 1.5vw solid #3498db;
|
|
border-radius: 50%;
|
|
width: 10vw;
|
|
height: 10vw;
|
|
animation: spin 2s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.video-container {
|
|
display: none;
|
|
width: 100%;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 2vw;
|
|
}
|
|
|
|
.video-thumbnail {
|
|
border-radius: 8px;
|
|
transition: transform 0.3s ease;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
|
|
background-color: #444;
|
|
aspect-ratio: 16/9;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.current-video {
|
|
width: 50vw;
|
|
z-index: 2;
|
|
box-shadow: 0 0 200px -10px #444;
|
|
}
|
|
|
|
.side-video {
|
|
width: 20vw;
|
|
opacity: 0.7;
|
|
z-index: 1;
|
|
}
|
|
|
|
.play-button {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 80px; /* Adjust size as needed */
|
|
height: 80px; /* Adjust size as needed */
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E");
|
|
background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-size: 50%; /* Adjust icon size within button */
|
|
border-radius: 50%; /* Circular button */
|
|
cursor: pointer;
|
|
z-index: 3; /* Ensure it's above the video thumbnails */
|
|
border: 2px solid white;
|
|
box-shadow: 0 0 15px rgba(0,0,0,0.7);
|
|
}
|
|
|
|
#video-overlay-container {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: black;
|
|
z-index: 10000; /* Above other page content */
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
#video-overlay-container .video-player {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
}
|
|
|
|
#video-overlay-container #back-button { /* Back button is now inside the container */
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
z-index: 1; /* z-index relative to siblings in container */
|
|
padding: 10px 20px;
|
|
font-size: 16px;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
color: white;
|
|
border: 1px solid white;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
opacity: 1; /* Visible by default */
|
|
transition: opacity 0.3s ease-in-out; /* Smooth transition */
|
|
}
|
|
|
|
#video-overlay-container #back-button.button-hidden {
|
|
opacity: 0; /* Class to hide the button */
|
|
}
|
|
|
|
#custom-video-controls {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
padding: 10px;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
align-items: center;
|
|
z-index: 1; /* Above video, but below back button if it were in the same direct stacking context */
|
|
opacity: 1;
|
|
transition: opacity 0.3s ease-in-out;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
#custom-video-controls.controls-hidden {
|
|
opacity: 0;
|
|
}
|
|
|
|
#custom-play-pause-button {
|
|
background: none;
|
|
border: none;
|
|
color: white;
|
|
font-size: 1.5em; /* Adjust size as needed */
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
#custom-seek-bar {
|
|
flex-grow: 1;
|
|
cursor: pointer;
|
|
accent-color: #3498db; /* Optional: color for the seek bar thumb and progress */
|
|
}
|
|
</style>
|
|
<script>
|
|
function hideLoader() {
|
|
$(".loader").hide();
|
|
$(".video-container").css("display", "flex");
|
|
}
|
|
|
|
let currentVideo = null;
|
|
let videoElement = null;
|
|
let overlayContainer = null;
|
|
let inactivityTimer = null;
|
|
let backButton = null;
|
|
let customControls = null;
|
|
let playPauseButton = null;
|
|
let seekBar = null;
|
|
|
|
function exitVideoPlayback() {
|
|
if (videoElement && videoElement.pause) {
|
|
videoElement.pause();
|
|
}
|
|
clearTimeout(inactivityTimer);
|
|
if (overlayContainer) {
|
|
overlayContainer.css('cursor', 'default');
|
|
overlayContainer.off('mousemove.inactivityControls');
|
|
// Detach document-level fullscreen listener specific to this playback
|
|
$(document).off('fullscreenchange.videoPlayback webkitfullscreenchange.videoPlayback mozfullscreenchange.videoPlayback MSFullscreenChange.videoPlayback', handleFullscreenChange);
|
|
overlayContainer.remove();
|
|
}
|
|
// Attempt to exit fullscreen if the document is still in fullscreen mode
|
|
// and our container was likely the one in fullscreen.
|
|
if (document.fullscreenElement || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement) {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen().catch(() => {});
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen();
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen();
|
|
} else if (document.msExitFullscreen) {
|
|
document.msExitFullscreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
function showControlsAndResetTimer() {
|
|
backButton.removeClass('button-hidden');
|
|
customControls.removeClass('controls-hidden');
|
|
overlayContainer.css('cursor', 'default'); // Show cursor
|
|
clearTimeout(inactivityTimer);
|
|
inactivityTimer = setTimeout(function() {
|
|
backButton.addClass('button-hidden');
|
|
customControls.addClass('controls-hidden');
|
|
overlayContainer.css('cursor', 'none'); // Hide cursor
|
|
}, 3000); // 3 seconds
|
|
}
|
|
|
|
// --- Moved Helper Function Definitions ---
|
|
function handlePlayPauseClick() {
|
|
if (videoElement.paused) {
|
|
videoElement.play();
|
|
} else {
|
|
videoElement.pause();
|
|
}
|
|
}
|
|
|
|
function updatePlayPauseButtonState() {
|
|
if (!playPauseButton) return; // Ensure button exists
|
|
if (videoElement.paused) {
|
|
playPauseButton.text('►'); // Play icon
|
|
} else {
|
|
playPauseButton.text('❚❚'); // Pause icon
|
|
}
|
|
}
|
|
|
|
function handleVideoLoadedMetadata() {
|
|
if (!seekBar) return; // Ensure seekbar exists
|
|
seekBar.attr('max', videoElement.duration);
|
|
}
|
|
|
|
function handleVideoTimeUpdate() {
|
|
if (!seekBar) return; // Ensure seekbar exists
|
|
seekBar.val(videoElement.currentTime);
|
|
const percentage = (videoElement.currentTime / videoElement.duration) * 100;
|
|
seekBar.css('background', `linear-gradient(to right, #3498db ${percentage}%, #555 ${percentage}%)`);
|
|
}
|
|
|
|
function handleSeekBarInput() {
|
|
if (!seekBar) return; // Ensure seekbar exists
|
|
videoElement.currentTime = seekBar.val();
|
|
}
|
|
|
|
function handleFullscreenChange() {
|
|
const isActuallyFullscreen = document.fullscreenElement || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement;
|
|
if (!isActuallyFullscreen && overlayContainer && overlayContainer.length && !overlayContainer.is(document.fullscreenElement)) {
|
|
if (overlayContainer.is(':visible')) {
|
|
exitVideoPlayback();
|
|
}
|
|
}
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
// Pre-set all thumbnails to a placeholder state
|
|
$(".video-thumbnail").attr("src", "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 16 9'%3E%3C/svg%3E");
|
|
|
|
$.getJSON("/api/homepage", function(data) {
|
|
currentVideo = data.currentVideo;
|
|
// previousVideo = data.previousVideo;
|
|
// nextVideo = data.nextVideo;
|
|
//
|
|
// // Set thumbnails
|
|
$("#current-thumb").attr("src", currentVideo.thumbnail);
|
|
// $("#prev-thumb").attr("src", previousVideo.thumbnail);
|
|
// $("#next-thumb").attr("src", nextVideo.thumbnail);
|
|
|
|
// Hide loader and show videos
|
|
hideLoader();
|
|
})
|
|
|
|
$("#play-button").click(function() {
|
|
if (currentVideo && currentVideo.url) {
|
|
// Create the overlay container
|
|
overlayContainer = $("<div id='video-overlay-container'></div>").appendTo("body");
|
|
|
|
// Create video element and append to container
|
|
videoElement = $("<video autoplay class='video-player'></video>") // Removed 'controls' attribute
|
|
.attr("src", currentVideo.url)
|
|
.appendTo(overlayContainer)[0];
|
|
|
|
// Create back button and append to container
|
|
backButton = $("<button id='back-button'>Back</button>")
|
|
.appendTo(overlayContainer);
|
|
|
|
// Create custom video controls container
|
|
customControls = $("<div id='custom-video-controls'></div>").appendTo(overlayContainer);
|
|
playPauseButton = $("<button id='custom-play-pause-button'>❚❚</button>").appendTo(customControls); // Assign to global var
|
|
seekBar = $("<input type='range' id='custom-seek-bar' value='0' />").appendTo(customControls); // Assign to global var
|
|
|
|
// Remove local inactivityTimer declaration, it's global now
|
|
// let inactivityTimer;
|
|
|
|
// --- Setup Inactivity Controls ---
|
|
overlayContainer.on('mousemove.inactivityControls', showControlsAndResetTimer);
|
|
showControlsAndResetTimer(); // Initial call
|
|
|
|
// --- Setup Custom Video Controls ---
|
|
playPauseButton.click(handlePlayPauseClick);
|
|
$(videoElement).on('play', updatePlayPauseButtonState);
|
|
$(videoElement).on('pause', updatePlayPauseButtonState);
|
|
$(videoElement).on('loadedmetadata', handleVideoLoadedMetadata);
|
|
$(videoElement).on('timeupdate', handleVideoTimeUpdate);
|
|
seekBar.on('input', handleSeekBarInput);
|
|
// Initial call to set play/pause button state, especially if autoplay is effective
|
|
updatePlayPauseButtonState();
|
|
|
|
// --- Setup Video End and Back Button ---
|
|
$(videoElement).on('ended', exitVideoPlayback);
|
|
backButton.click(exitVideoPlayback);
|
|
|
|
// --- Setup Fullscreen Change Listener ---
|
|
// Detach any previous listeners first (using the specific named handler for accuracy if needed, but general works too)
|
|
$(document).off('fullscreenchange.videoPlayback webkitfullscreenchange.videoPlayback mozfullscreenchange.videoPlayback MSFullscreenChange.videoPlayback');
|
|
$(document).on('fullscreenchange.videoPlayback webkitfullscreenchange.videoPlayback mozfullscreenchange.videoPlayback MSFullscreenChange.videoPlayback', handleFullscreenChange);
|
|
|
|
// --- Request Fullscreen ---
|
|
const containerEl = overlayContainer[0];
|
|
if (containerEl.requestFullscreen) {
|
|
containerEl.requestFullscreen();
|
|
} else if (containerEl.mozRequestFullScreen) { /* Firefox */
|
|
containerEl.mozRequestFullScreen();
|
|
} else if (containerEl.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
|
|
containerEl.webkitRequestFullscreen();
|
|
} else if (containerEl.msRequestFullscreen) { /* IE/Edge */
|
|
containerEl.msRequestFullscreen();
|
|
}
|
|
// NOTE: exitVideoPlayback was defined above.
|
|
// The original snippet showed its definition here, it's now grouped with other helpers.
|
|
}
|
|
});
|
|
})
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="loader" id="loader"></div>
|
|
<div class="video-container">
|
|
<img id="prev-thumb" class="video-thumbnail side-video" alt="Previous Video">
|
|
<img id="current-thumb" class="video-thumbnail current-video" alt="Current Video">
|
|
<img id="next-thumb" class="video-thumbnail side-video" alt="Next Video">
|
|
<div class="play-button" id="play-button"></div>
|
|
</div>
|
|
</body>
|
|
</html>
|