fix:(video.js) support embed functionality and ensure videos play independently on the same page

This commit is contained in:
Yiannis Christodoulou 2025-09-19 08:31:38 +03:00
parent 2c6484b6ca
commit 222c728909
5 changed files with 162 additions and 17 deletions

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VideoJS</title>
</head>
<body>
<!-- <div id="video-js-root-main"></div> -->
<div id="video-js-root-embed" class="video-js-root-embed"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@ -7,14 +7,8 @@
<title>VideoJS</title>
</head>
<body>
<h1>Main Video Player</h1>
<div id="video-js-root-main"></div>
<hr />
<h1>Embed Video Player</h1>
<div id="video-js-root-embed"></div>
<div id="video-js-root-main" class="video-js-root-main"></div>
<!-- <div id="video-js-root-embed"></div> -->
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@ -22,6 +22,20 @@ html {
border-radius: 12px !important;
}
/* Fullscreen video styles for embedded video player */
.video-js-root-embed .video-js video {
width: 100vw !important;
height: 100vh !important;
object-fit: cover !important;
border-radius: 0 !important;
}
.video-js-root-embed .video-js .vjs-poster {
border-radius: 0 !important;
width: 100vw !important;
height: 100vh !important;
object-fit: cover !important;
}
.video-js div.vjs-control-bar {
background: transparent !important;
background-color: transparent !important;
@ -41,10 +55,32 @@ html {
padding: 0 20px;
box-sizing: border-box;
}
/* Fullscreen styles for embedded video player */
.video-js-root-embed .video-container {
width: 100vw;
height: 100vh;
max-width: none;
margin: 0;
padding: 0;
box-sizing: border-box;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
}
.video-js.vjs-fluid {
width: 100% !important;
max-width: 100% !important;
}
/* Fullscreen fluid styles for embedded video player */
.video-js-root-embed .video-js.vjs-fluid {
width: 100vw !important;
height: 100vh !important;
max-width: none !important;
max-height: none !important;
}
.vjs-autoplay-toggle .vjs-autoplay-icon svg {
width: 100%;
height: 100%;
@ -735,6 +771,32 @@ button {
height: 100% !important;
border-radius: 12px;
}
/* Fullscreen video-js player styles for embedded video player */
.video-js-root-embed .video-js {
width: 100vw !important;
height: 100vh !important;
border-radius: 0;
position: relative;
}
/* Prevent page scrolling when embed is active */
.video-js-root-embed {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
background: #000;
}
html.video-js-root-embed-active,
body.video-js-root-embed-active {
margin: 0;
padding: 0;
overflow: hidden;
}
.video-chapter {
position: absolute;
top: auto;

View File

@ -1047,6 +1047,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
},
siteUrl: '',
nextLink: 'https://demo.mediacms.io/view?m=YjGJafibO',
urlAutoplay: true,
},
[]
);
@ -1190,6 +1191,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
previewSprite: mediaData?.previewSprite || {},
related_media: mediaData.data?.related_media || [],
nextLink: mediaData?.nextLink || null,
urlAutoplay: mediaData?.urlAutoplay || true,
sources: getVideoSources(),
};
}, [mediaData]);
@ -1419,13 +1421,13 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
// Player dimensions - removed for responsive design
// Autoplay behavior: Use 'muted' to comply with browser policies
autoplay: 'play', // Set to true/false to show poster image initially (true/false, play, muted, any)
autoplay: 'muted', // Auto-start muted to comply with browser policies (true/false, play, muted, any)
// Start video over when it ends
loop: false,
// Start video muted
muted: false,
// Start video muted (check URL parameter or default)
muted: mediaData.urlMuted || false,
// Poster image URL displayed before video starts
poster: currentVideo.poster,
@ -1691,6 +1693,54 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
// Set up auto-save for preference changes
userPreferences.current.setupAutoSave(playerRef.current);
// Expose the player instance globally for timestamp functionality
if (typeof window !== 'undefined') {
if (!window.videojsPlayers) {
window.videojsPlayers = {};
}
window.videojsPlayers[videoId] = playerRef.current;
}
// Call the onPlayerInitCallback if provided via MEDIA_DATA
if (mediaData.onPlayerInitCallback && typeof mediaData.onPlayerInitCallback === 'function') {
mediaData.onPlayerInitCallback({ player: playerRef.current }, playerRef.current.el());
}
// Handle URL timestamp parameter
if (mediaData.urlTimestamp !== null && mediaData.urlTimestamp >= 0) {
const timestamp = mediaData.urlTimestamp;
// Wait for video metadata to be loaded before seeking
if (playerRef.current.readyState() >= 1) {
// Metadata is already loaded, seek immediately
if (timestamp < playerRef.current.duration()) {
playerRef.current.currentTime(timestamp);
} else if (timestamp >= 0) {
playerRef.current.play();
}
} else {
// Wait for metadata to load
playerRef.current.one('loadedmetadata', () => {
if (timestamp >= 0 && timestamp < playerRef.current.duration()) {
playerRef.current.currentTime(timestamp);
} else if (timestamp >= 0) {
playerRef.current.play();
}
});
}
}
// Handle URL autoplay parameter or auto-start on page load
if (mediaData?.urlAutoplay) {
playerRef.current.play();
} else {
// Auto-start video on page load/reload (muted to comply with browser policies)
playerRef.current.play().catch((error) => {
console.log(' Browser prevented autoplay (normal behavior):', error.message);
// Fallback: ensure video is ready to play when user interacts
});
}
const setupMobilePlayPause = () => {
const playerEl = playerRef.current.el();
const videoEl = playerEl.querySelector('video');
@ -2268,14 +2318,18 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
const newTime = Math.min(currentTime + seekAmount, duration);
playerRef.current.currentTime(newTime);
customComponents.current.seekIndicator.show('forward', seekAmount);
if (customComponents.current.seekIndicator) {
customComponents.current.seekIndicator.show('forward', seekAmount);
}
} else if (event.key === 'ArrowLeft' || event.keyCode === 37) {
event.preventDefault();
const currentTime = playerRef.current.currentTime();
const newTime = Math.max(currentTime - seekAmount, 0);
playerRef.current.currentTime(newTime);
customComponents.current.seekIndicator.show('backward', seekAmount);
if (customComponents.current.seekIndicator) {
customComponents.current.seekIndicator.show('backward', seekAmount);
}
}
};
@ -2482,7 +2536,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
playerRef.current.on('play', () => {
console.log('Video started playing');
// Only show play indicator if not changing quality
if (!playerRef.current.isChangingQuality) {
if (!playerRef.current.isChangingQuality && customComponents.current.seekIndicator) {
customComponents.current.seekIndicator.show('play');
}
});
@ -2490,7 +2544,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
playerRef.current.on('pause', () => {
console.log('Video paused');
// Only show pause indicator if not changing quality
if (!playerRef.current.isChangingQuality) {
if (!playerRef.current.isChangingQuality && customComponents.current.seekIndicator) {
customComponents.current.seekIndicator.show('pause');
}
});

View File

@ -9,29 +9,50 @@ import VideoJS from './VideoJS.jsx';
const mountComponents = () => {
// Mount main video player
const rootContainerMain = document.getElementById('video-js-root-main');
if (rootContainerMain) {
if (rootContainerMain && !rootContainerMain.hasChildNodes()) {
const rootMain = createRoot(rootContainerMain);
rootMain.render(
<StrictMode>
<VideoJS videoId="video-main" />
</StrictMode>
);
console.log('Mounted main VideoJS player');
}
// Mount embed video player
const rootContainerEmbed = document.getElementById('video-js-root-embed');
if (rootContainerEmbed) {
if (rootContainerEmbed && !rootContainerEmbed.hasChildNodes()) {
const rootEmbed = createRoot(rootContainerEmbed);
rootEmbed.render(
<StrictMode>
<VideoJS videoId="video-embed" />
</StrictMode>
);
console.log('Mounted embed VideoJS player');
}
};
// Expose the mounting function globally for manual triggering
window.triggerVideoJSMount = mountComponents;
// Listen for custom events to trigger mounting
document.addEventListener('triggerVideoJSMount', () => {
console.log('Received triggerVideoJSMount event, attempting to mount VideoJS components...');
mountComponents();
});
// Initial mount
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', mountComponents);
} else {
mountComponents();
}
// Also periodically check for new containers (as a fallback)
setInterval(() => {
const embedContainer = document.getElementById('video-js-root-embed');
if (embedContainer && !embedContainer.hasChildNodes()) {
console.log('Found unmounted embed container during periodic check, mounting...');
mountComponents();
}
}, 1000);