mirror of
https://github.com/arthur-pbty/syncfilm.git
synced 2026-06-03 23:36:38 +02:00
315 lines
9.6 KiB
JavaScript
315 lines
9.6 KiB
JavaScript
// Select DOM elements
|
|
const video = document.getElementById("video");
|
|
const playPauseBtn = document.getElementById("play-pause");
|
|
const progressBar = document.getElementById("progress-bar");
|
|
const currentTimeElem = document.getElementById("current-time");
|
|
const durationElem = document.getElementById("duration");
|
|
const muteBtn = document.getElementById("mute");
|
|
const volumeSlider = document.getElementById("volume");
|
|
const loadingElem = document.getElementById("loading");
|
|
const fullscreenBtn = document.getElementById("fullscreen");
|
|
const rewindBtn = document.getElementById("rewind");
|
|
const forwardBtn = document.getElementById("forward");
|
|
const playIcon = document.getElementById("play-icon");
|
|
const pauseIcon = document.getElementById("pause-icon");
|
|
const soundIcon = document.getElementById("sound-icon");
|
|
const muteIcon = document.getElementById("mute-icon");
|
|
const videoPlayer = document.getElementById("video-player");
|
|
|
|
const socket = io(); // Initialize socket.io connection
|
|
|
|
// Prompt for the user's name if not already stored
|
|
let userName = localStorage.getItem("userName");
|
|
if (!userName) {
|
|
userName = prompt("Enter your name:");
|
|
if (userName) {
|
|
localStorage.setItem("userName", userName);
|
|
socket.emit("setName", userName); // Send the name to the server
|
|
}
|
|
} else {
|
|
socket.emit("setName", userName); // Send the stored name to the server
|
|
}
|
|
|
|
// Handle synchronization actions from the server
|
|
socket.on("make", (data) => {
|
|
controls.style.display = "none";
|
|
loadingElem.style.display = "block"; // Show loading for all users
|
|
video.pause();
|
|
video.currentTime = data.time;
|
|
socket.emit("ok", data); // Acknowledge the action
|
|
});
|
|
|
|
// Handle synchronization completion
|
|
socket.on("allOk", (data) => {
|
|
loadingElem.style.display = "none"; // Hide loading for all users
|
|
controls.style.display = "flex";
|
|
if (data.action === "play") {
|
|
video.play(); // Resume playback
|
|
playIcon.style.opacity = "0";
|
|
pauseIcon.style.opacity = "1";
|
|
} else {
|
|
video.pause(); // Pause the video
|
|
playIcon.style.opacity = "1";
|
|
pauseIcon.style.opacity = "0";
|
|
}
|
|
});
|
|
|
|
// Display notifications (e.g., user connected/disconnected)
|
|
function showNotification(message, color) {
|
|
const notificationContainer = document.getElementById("notification-container");
|
|
if (!notificationContainer) {
|
|
const container = document.createElement("div");
|
|
container.id = "notification-container";
|
|
container.style.position = "fixed";
|
|
container.style.top = "20px";
|
|
container.style.right = "20px";
|
|
container.style.zIndex = "1000";
|
|
container.style.display = "flex";
|
|
container.style.flexDirection = "column";
|
|
container.style.gap = "10px";
|
|
document.body.appendChild(container);
|
|
}
|
|
|
|
const notification = document.createElement("div");
|
|
notification.textContent = message;
|
|
notification.style.backgroundColor = color;
|
|
notification.style.color = "white";
|
|
notification.style.padding = "10px 20px";
|
|
notification.style.borderRadius = "5px";
|
|
notification.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)";
|
|
notification.style.animation = "fadeOut 3s forwards";
|
|
document.getElementById("notification-container").appendChild(notification);
|
|
|
|
setTimeout(() => {
|
|
notification.remove();
|
|
}, 3000);
|
|
}
|
|
|
|
// Add fade-out animation for notifications
|
|
const style = document.createElement("style");
|
|
style.textContent = `
|
|
@keyframes fadeOut {
|
|
0% { opacity: 1; }
|
|
90% { opacity: 1; }
|
|
100% { opacity: 0; transform: translateY(-10px); }
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
|
|
// Listen for notifications from the server
|
|
socket.on("notification", (data) => {
|
|
showNotification(data.message, data.color);
|
|
});
|
|
|
|
// Format time in minutes:seconds
|
|
function formatTime(seconds) {
|
|
const minutes = Math.floor(seconds / 60);
|
|
seconds = Math.floor(seconds % 60);
|
|
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`;
|
|
}
|
|
|
|
// Get the current video state (play/pause and time)
|
|
function getVideoData() {
|
|
return {
|
|
action: video.paused ? "pause" : "play",
|
|
time: video.currentTime,
|
|
};
|
|
}
|
|
|
|
// Rewind the video by 10 seconds
|
|
rewindBtn.addEventListener("click", () => {
|
|
video.currentTime = Math.max(0, video.currentTime - 10);
|
|
socket.emit("action", getVideoData());
|
|
});
|
|
|
|
// Fast forward the video by 10 seconds
|
|
forwardBtn.addEventListener("click", () => {
|
|
video.currentTime = Math.min(video.duration, video.currentTime + 10);
|
|
socket.emit("action", getVideoData());
|
|
});
|
|
|
|
// Toggle play/pause
|
|
playPauseBtn.addEventListener("click", () => {
|
|
if (video.paused) {
|
|
video.play();
|
|
socket.emit("action", getVideoData());
|
|
playIcon.style.opacity = "0";
|
|
pauseIcon.style.opacity = "1";
|
|
} else {
|
|
video.pause();
|
|
socket.emit("action", getVideoData());
|
|
playIcon.style.opacity = "1";
|
|
pauseIcon.style.opacity = "0";
|
|
}
|
|
});
|
|
|
|
// Toggle play/pause by clicking on the video
|
|
video.addEventListener("click", () => {
|
|
playPauseBtn.click();
|
|
});
|
|
|
|
// Add keyboard shortcut for play/pause
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.code === "Space") {
|
|
event.preventDefault(); // Prevent scrolling
|
|
playPauseBtn.click();
|
|
}
|
|
});
|
|
|
|
// Update progress bar and current time display
|
|
let isDragging = false;
|
|
|
|
video.addEventListener("timeupdate", () => {
|
|
if (!isDragging) {
|
|
progressBar.value = (video.currentTime / video.duration) * 100;
|
|
currentTimeElem.textContent = formatTime(video.currentTime);
|
|
}
|
|
});
|
|
|
|
// Update video time while dragging the progress bar
|
|
progressBar.addEventListener("input", () => {
|
|
isDragging = true;
|
|
currentTimeElem.textContent = formatTime(
|
|
(progressBar.value / 100) * video.duration
|
|
);
|
|
});
|
|
|
|
// Seek to a specific time when progress bar is released
|
|
progressBar.addEventListener("change", () => {
|
|
video.currentTime = (progressBar.value / 100) * video.duration;
|
|
isDragging = false;
|
|
socket.emit("action", getVideoData());
|
|
});
|
|
|
|
// Initialize video duration display
|
|
video.addEventListener("loadedmetadata", () => {
|
|
durationElem.textContent = formatTime(video.duration);
|
|
progressBar.value = 0;
|
|
currentTimeElem.textContent = "0:00";
|
|
});
|
|
|
|
// Reset progress bar when loading a new video
|
|
video.addEventListener("loadstart", () => {
|
|
progressBar.value = 0;
|
|
currentTimeElem.textContent = "0:00";
|
|
});
|
|
|
|
// Restore saved volume settings
|
|
const savedVolume = localStorage.getItem("videoVolume");
|
|
if (savedVolume !== null) {
|
|
video.volume = savedVolume;
|
|
volumeSlider.value = savedVolume * 100;
|
|
}
|
|
|
|
// Adjust volume and save the setting
|
|
volumeSlider.addEventListener("input", () => {
|
|
const newVolume = volumeSlider.value / 100;
|
|
video.volume = newVolume;
|
|
localStorage.setItem("videoVolume", newVolume);
|
|
});
|
|
|
|
// Toggle mute/unmute
|
|
muteBtn.addEventListener("click", () => {
|
|
video.muted = !video.muted;
|
|
if (video.muted) {
|
|
soundIcon.style.display = "none";
|
|
muteIcon.style.display = "block";
|
|
localStorage.setItem("videoMuted", "true");
|
|
} else {
|
|
soundIcon.style.display = "block";
|
|
muteIcon.style.display = "none";
|
|
localStorage.setItem("videoMuted", "false");
|
|
}
|
|
});
|
|
|
|
// Restore mute state on page load
|
|
const savedMuted = localStorage.getItem("videoMuted");
|
|
if (savedMuted === "true") {
|
|
video.muted = true;
|
|
soundIcon.style.display = "none";
|
|
muteIcon.style.display = "block";
|
|
}
|
|
|
|
// Show/hide controls on hover
|
|
let hideControlsTimeout;
|
|
|
|
function showControls() {
|
|
controls.style.opacity = "1";
|
|
controls.style.visibility = "visible";
|
|
if (hideControlsTimeout) {
|
|
clearTimeout(hideControlsTimeout);
|
|
}
|
|
hideControlsTimeout = setTimeout(hideControls, 3000);
|
|
}
|
|
|
|
function hideControls() {
|
|
controls.style.opacity = "0";
|
|
controls.style.visibility = "hidden";
|
|
}
|
|
|
|
videoPlayer.addEventListener("mousemove", showControls);
|
|
videoPlayer.addEventListener("mouseleave", hideControls);
|
|
|
|
// Handle fullscreen mode
|
|
let isFullscreen = false;
|
|
|
|
function enterFullscreen(element) {
|
|
if (element.requestFullscreen) {
|
|
element.requestFullscreen();
|
|
} else if (element.mozRequestFullScreen) {
|
|
element.mozRequestFullScreen();
|
|
} else if (element.webkitRequestFullscreen) {
|
|
element.webkitRequestFullscreen();
|
|
} else if (element.msRequestFullscreen) {
|
|
element.msRequestFullscreen();
|
|
}
|
|
}
|
|
|
|
function exitFullscreen() {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen();
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen();
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen();
|
|
} else if (document.msExitFullscreen) {
|
|
document.msExitFullscreen();
|
|
}
|
|
}
|
|
|
|
function handleFullscreenChange() {
|
|
isFullscreen =
|
|
document.fullscreenElement ||
|
|
document.mozFullScreenElement ||
|
|
document.webkitFullscreenElement ||
|
|
document.msFullscreenElement;
|
|
|
|
if (isFullscreen) {
|
|
videoPlayer.classList.add("fullscreen");
|
|
} else {
|
|
videoPlayer.classList.remove("fullscreen");
|
|
}
|
|
}
|
|
|
|
// Listen for fullscreen changes
|
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
document.addEventListener("mozfullscreenchange", handleFullscreenChange);
|
|
document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
|
|
document.addEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
|
|
// Exit fullscreen on Escape key
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape" && isFullscreen) {
|
|
exitFullscreen();
|
|
}
|
|
});
|
|
|
|
// Toggle fullscreen mode
|
|
fullscreenBtn.addEventListener("click", () => {
|
|
if (!isFullscreen) {
|
|
enterFullscreen(videoPlayer);
|
|
} else {
|
|
exitFullscreen();
|
|
}
|
|
});
|