mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-05 23:18:53 -05:00
Adds a method to reset the control bar to its default auto-hide behavior after the end screen is hidden, when auto-playing the next video, and during cleanup. Ensures the control bar does not remain visible unintentionally after video end or transitions.
235 lines
8.6 KiB
JavaScript
235 lines
8.6 KiB
JavaScript
import EndScreenOverlay from '../components/overlays/EndScreenOverlay';
|
|
import AutoplayCountdownOverlay from '../components/overlays/AutoplayCountdownOverlay';
|
|
|
|
export class EndScreenHandler {
|
|
constructor(player, options) {
|
|
this.player = player;
|
|
this.options = options;
|
|
this.endScreen = null;
|
|
this.autoplayCountdown = null;
|
|
|
|
this.setupEndScreenHandling();
|
|
}
|
|
|
|
setupEndScreenHandling() {
|
|
// Handle video ended event
|
|
this.player.on('ended', () => {
|
|
this.handleVideoEnded();
|
|
});
|
|
|
|
// Hide end screen and autoplay countdown when user wants to replay
|
|
const hideEndScreenAndStopCountdown = () => {
|
|
if (this.endScreen) {
|
|
this.endScreen.hide();
|
|
}
|
|
if (this.autoplayCountdown) {
|
|
this.autoplayCountdown.stopCountdown();
|
|
}
|
|
|
|
// Reset control bar to normal auto-hide behavior
|
|
this.resetControlBarBehavior();
|
|
};
|
|
|
|
this.player.on('play', hideEndScreenAndStopCountdown);
|
|
this.player.on('seeking', hideEndScreenAndStopCountdown);
|
|
|
|
// Reset control bar when playing after ended state
|
|
this.player.on('playing', () => {
|
|
// Only reset if we're coming from ended state (time near 0)
|
|
if (this.player.currentTime() < 1) {
|
|
setTimeout(() => {
|
|
this.player.userActive(false);
|
|
}, 1000); // Hide controls after 1 second
|
|
}
|
|
});
|
|
}
|
|
|
|
// New method to reset control bar to default behavior
|
|
resetControlBarBehavior() {
|
|
const controlBar = this.player.getChild('controlBar');
|
|
if (controlBar && controlBar.el()) {
|
|
// Remove the forced visible styles
|
|
controlBar.el().style.opacity = '';
|
|
controlBar.el().style.pointerEvents = '';
|
|
|
|
// Let video.js handle the control bar visibility normally
|
|
// Force the player to be inactive after a short delay
|
|
setTimeout(() => {
|
|
if (!this.player.paused() && !this.player.ended()) {
|
|
this.player.userActive(false);
|
|
}
|
|
}, 500);
|
|
}
|
|
}
|
|
|
|
handleVideoEnded() {
|
|
const { isEmbedPlayer, userPreferences, mediaData, currentVideo, relatedVideos, goToNextVideo } = this.options;
|
|
|
|
// For embed players, show big play button when video ends
|
|
if (isEmbedPlayer) {
|
|
const bigPlayButton = this.player.getChild('bigPlayButton');
|
|
if (bigPlayButton) {
|
|
bigPlayButton.show();
|
|
}
|
|
}
|
|
|
|
// Keep controls active after video ends
|
|
setTimeout(() => {
|
|
if (this.player && !this.player.isDisposed()) {
|
|
const playerEl = this.player.el();
|
|
if (playerEl) {
|
|
// Hide poster image when end screen is shown - multiple approaches
|
|
const posterImage = this.player.getChild('posterImage');
|
|
if (posterImage) {
|
|
posterImage.hide();
|
|
posterImage.el().style.display = 'none';
|
|
posterImage.el().style.visibility = 'hidden';
|
|
posterImage.el().style.opacity = '0';
|
|
}
|
|
|
|
// Hide all poster elements directly
|
|
const posterElements = playerEl.querySelectorAll('.vjs-poster');
|
|
posterElements.forEach((posterEl) => {
|
|
posterEl.style.display = 'none';
|
|
posterEl.style.visibility = 'hidden';
|
|
posterEl.style.opacity = '0';
|
|
});
|
|
|
|
// Set player background to dark to match end screen
|
|
playerEl.style.backgroundColor = '#000';
|
|
|
|
// Keep video element visible but ensure it doesn't show poster
|
|
const videoEl = playerEl.querySelector('video');
|
|
if (videoEl) {
|
|
// Remove poster attribute from video element
|
|
videoEl.removeAttribute('poster');
|
|
videoEl.style.backgroundColor = '#000';
|
|
}
|
|
|
|
// Keep the visual ended state but ensure controls work
|
|
const controlBar = this.player.getChild('controlBar');
|
|
if (controlBar) {
|
|
controlBar.show();
|
|
controlBar.el().style.opacity = '1';
|
|
controlBar.el().style.pointerEvents = 'auto';
|
|
|
|
// Style progress bar to match dark end screen background
|
|
const progressControl = controlBar.getChild('progressControl');
|
|
if (progressControl) {
|
|
progressControl.show();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, 50);
|
|
|
|
// Check if autoplay is enabled and there's a next video
|
|
const isAutoplayEnabled = userPreferences.getAutoplayPreference();
|
|
const hasNextVideo = mediaData.nextLink !== null;
|
|
|
|
if (!isEmbedPlayer && isAutoplayEnabled && hasNextVideo) {
|
|
// If it's a playlist, skip countdown and play directly
|
|
if (currentVideo.isPlayList) {
|
|
this.cleanupOverlays();
|
|
goToNextVideo();
|
|
} else {
|
|
this.showAutoplayCountdown(relatedVideos, goToNextVideo);
|
|
}
|
|
} else {
|
|
// Autoplay disabled or no next video - show regular end screen
|
|
this.showEndScreen(relatedVideos);
|
|
}
|
|
}
|
|
|
|
showAutoplayCountdown(relatedVideos, goToNextVideo) {
|
|
// Get next video data for countdown display - find the next video in related videos
|
|
let nextVideoData = {
|
|
title: 'Next Video',
|
|
author: '',
|
|
duration: 0,
|
|
thumbnail: '',
|
|
};
|
|
|
|
// Try to find the next video by URL matching or just use the first related video
|
|
if (relatedVideos.length > 0) {
|
|
const nextVideo = relatedVideos[0];
|
|
nextVideoData = {
|
|
title: nextVideo.title || 'Next Video',
|
|
author: nextVideo.author || '',
|
|
duration: nextVideo.duration || 0,
|
|
thumbnail: nextVideo.thumbnail || '',
|
|
};
|
|
}
|
|
|
|
// Clean up any existing overlays
|
|
this.cleanupOverlays();
|
|
|
|
// Show autoplay countdown immediately!
|
|
this.autoplayCountdown = new AutoplayCountdownOverlay(this.player, {
|
|
nextVideoData: nextVideoData,
|
|
countdownSeconds: 5,
|
|
onPlayNext: () => {
|
|
// Reset control bar when auto-playing next video
|
|
this.resetControlBarBehavior();
|
|
goToNextVideo();
|
|
},
|
|
onCancel: () => {
|
|
// Hide countdown and show end screen instead
|
|
if (this.autoplayCountdown) {
|
|
this.player.removeChild(this.autoplayCountdown);
|
|
this.autoplayCountdown = null;
|
|
}
|
|
this.showEndScreen(relatedVideos);
|
|
},
|
|
});
|
|
|
|
this.player.addChild(this.autoplayCountdown);
|
|
// Start countdown immediately without any delay
|
|
setTimeout(() => {
|
|
if (this.autoplayCountdown && !this.autoplayCountdown.isDisposed()) {
|
|
this.autoplayCountdown.startCountdown();
|
|
}
|
|
}, 0);
|
|
}
|
|
|
|
showEndScreen(relatedVideos) {
|
|
// Prevent creating multiple end screens
|
|
if (this.endScreen) {
|
|
this.player.removeChild(this.endScreen);
|
|
this.endScreen = null;
|
|
}
|
|
|
|
// Show end screen with related videos
|
|
this.endScreen = new EndScreenOverlay(this.player, {
|
|
relatedVideos: relatedVideos,
|
|
});
|
|
|
|
// Store the data directly on the component as backup and update it
|
|
this.endScreen.relatedVideos = relatedVideos;
|
|
if (this.endScreen.setRelatedVideos) {
|
|
this.endScreen.setRelatedVideos(relatedVideos);
|
|
}
|
|
|
|
this.player.addChild(this.endScreen);
|
|
this.endScreen.show();
|
|
}
|
|
|
|
cleanupOverlays() {
|
|
// Clean up any existing overlays
|
|
if (this.endScreen) {
|
|
this.player.removeChild(this.endScreen);
|
|
this.endScreen = null;
|
|
}
|
|
if (this.autoplayCountdown) {
|
|
this.player.removeChild(this.autoplayCountdown);
|
|
this.autoplayCountdown = null;
|
|
}
|
|
}
|
|
|
|
cleanup() {
|
|
this.cleanupOverlays();
|
|
// Reset control bar on cleanup
|
|
this.resetControlBarBehavior();
|
|
}
|
|
}
|