fix: Improve autoplay countdown

This commit is contained in:
Yiannis Christodoulou 2025-09-29 00:21:44 +03:00
parent fcdeac4977
commit bb70888748
3 changed files with 184 additions and 541 deletions

View File

@ -1,11 +1,11 @@
/* Autoplay Countdown Overlay Styles */ /* Minimal Circular Countdown Overlay */
.vjs-autoplay-countdown-overlay { .vjs-autoplay-countdown-overlay {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: calc(100% - 46px); /* Account for control bar */ height: 100%;
background: rgba(0, 0, 0, 0.85); background: rgba(0, 0, 0, 0.7);
display: none; display: none;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -13,9 +13,8 @@
z-index: 100000; z-index: 100000;
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
backdrop-filter: blur(4px);
opacity: 0; opacity: 0;
transition: opacity 0.3s ease-in-out; transition: opacity 0.2s ease-out;
} }
.vjs-autoplay-countdown-overlay.autoplay-countdown-show { .vjs-autoplay-countdown-overlay.autoplay-countdown-show {
@ -23,522 +22,174 @@
} }
.autoplay-countdown-content { .autoplay-countdown-content {
background: linear-gradient(135deg, rgba(0, 0, 0, 0.95), rgba(20, 20, 20, 0.9));
border-radius: 20px;
padding: 50px;
max-width: 480px;
width: 100%;
text-align: center; text-align: center;
box-shadow:
0 20px 60px rgba(0, 0, 0, 0.4),
0 8px 32px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(20px);
position: relative;
overflow: hidden;
}
.autoplay-countdown-content::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
}
.autoplay-countdown-content::after {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 0, 0, 0.05) 0%, transparent 70%);
animation: backgroundPulse 4s ease-in-out infinite;
pointer-events: none;
}
@keyframes backgroundPulse {
0%,
100% {
opacity: 0.3;
transform: scale(1);
}
50% {
opacity: 0.6;
transform: scale(1.1);
}
}
.autoplay-countdown-header {
position: relative;
z-index: 2;
}
.autoplay-countdown-header h3 {
color: #fff;
font-size: 26px;
font-weight: 400;
margin: 0 0 10px 0;
line-height: 1.3;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.autoplay-countdown-header h3 span {
font-weight: 700;
}
.autoplay-countdown-video-info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 20px; gap: 12px;
text-align: center; max-width: 350px;
position: relative;
z-index: 2;
margin: 0 0 50px;
}
.next-video-thumbnail {
flex-shrink: 0;
width: 180px;
height: 101px;
border-radius: 12px;
overflow: hidden;
background: #333;
position: relative;
box-shadow:
0 12px 32px rgba(0, 0, 0, 0.4),
0 4px 16px rgba(0, 0, 0, 0.2);
border: 2px solid rgba(255, 255, 255, 0.1);
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
}
.next-video-thumbnail:hover {
transform: translateY(-4px) scale(1.02);
box-shadow:
0 16px 40px rgba(0, 0, 0, 0.5),
0 8px 24px rgba(0, 0, 0, 0.3);
}
.next-video-thumbnail img {
width: 100%; width: 100%;
height: 100%;
object-fit: cover;
display: block;
} }
.play-overlay { .countdown-label {
position: absolute; color: rgba(255, 255, 255, 0.8);
top: 50%; font-size: 14px;
left: 50%; font-weight: 400;
transform: translate(-50%, -50%); margin: 0;
background: rgba(0, 0, 0, 0.8); text-transform: uppercase;
border-radius: 50%; letter-spacing: 1px;
width: 64px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
color: white;
transition: all 0.3s ease;
box-shadow:
0 8px 24px rgba(0, 0, 0, 0.5),
0 4px 16px rgba(0, 0, 0, 0.3);
border: 3px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(8px);
}
.play-overlay:hover {
background: rgba(0, 0, 0, 0.9);
transform: translate(-50%, -50%) scale(1.1);
box-shadow:
0 12px 32px rgba(0, 0, 0, 0.6),
0 6px 20px rgba(0, 0, 0, 0.4);
}
.play-overlay svg {
margin-left: 4px;
width: 28px;
height: 28px;
}
.next-video-details {
flex-grow: 1;
min-width: 0;
text-align: center;
} }
.next-video-title { .next-video-title {
color: #999; color: #fff;
font-size: 18px; font-size: 18px;
font-weight: 500; font-weight: 600;
margin: 0 0; margin: 0 0 12px 0;
line-height: 1.4; line-height: 1.3;
max-width: 100%;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
letter-spacing: 0.5px;
}
.next-video-author {
color: #bbb;
font-size: 16px;
margin: 0 0 8px 0;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
}
.next-video-duration {
color: #999;
font-size: 14px;
margin: 0;
line-height: 1.2;
font-weight: 500;
}
.autoplay-countdown-actions {
display: flex;
gap: 24px;
justify-content: center;
align-items: center;
position: relative;
z-index: 2;
padding: 0;
margin-top: 8px;
}
button.autoplay-play-button,
button.autoplay-cancel-button {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
min-width: 140px;
height: 48px;
position: relative;
overflow: hidden;
text-transform: uppercase;
letter-spacing: 0.3px;
line-height: 1;
white-space: nowrap;
box-shadow:
0 6px 20px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
text-align: center; text-align: center;
} }
button.autoplay-play-button { .next-video-author {
background: linear-gradient(135deg, #ff0000, #e60000); color: rgba(255, 255, 255, 0.7);
color: #fff; font-size: 14px;
border: 1px solid rgba(255, 255, 255, 0.1); font-weight: 400;
margin: -8px 0 0 0;
line-height: 1.2;
} }
.autoplay-play-button::before { .circular-countdown {
content: ""; position: relative;
position: absolute; cursor: pointer;
top: 0; transition: transform 0.2s ease;
left: -100%; margin: 10px 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s ease;
} }
.autoplay-play-button:hover { .circular-countdown:hover {
background: linear-gradient(135deg, #ff1a1a, #cc0000); transform: scale(1.05);
transform: translateY(-2px);
box-shadow:
0 8px 25px rgba(255, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
} }
.autoplay-play-button:hover::before { .countdown-circle {
left: 100%; filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
} }
.autoplay-play-button:active { .countdown-progress {
transform: translateY(-1px); stroke-linecap: round;
box-shadow: stroke-dasharray: 282.74;
0 4px 15px rgba(255, 0, 0, 0.3), stroke-dashoffset: 282.74;
inset 0 1px 0 rgba(255, 255, 255, 0.2); }
.play-icon {
cursor: pointer;
transition: all 0.2s ease;
}
.circular-countdown:hover .play-icon circle {
fill: rgba(255, 255, 255, 1);
}
.circular-countdown:hover .play-icon path {
fill: #000;
} }
.autoplay-cancel-button { .autoplay-cancel-button {
background: linear-gradient(135deg, #404040, #2a2a2a); background: transparent;
color: #fff; border: 1px solid rgba(255, 255, 255, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.9);
box-shadow: padding: 10px 24px;
0 6px 20px rgba(0, 0, 0, 0.3), border-radius: 6px;
inset 0 1px 0 rgba(255, 255, 255, 0.1); font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 4px;
} }
.autoplay-cancel-button:hover { .autoplay-cancel-button:hover {
background: linear-gradient(135deg, #505050, #3a3a3a); background: rgba(255, 255, 255, 0.1);
transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.5);
box-shadow: color: #fff;
0 8px 25px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.autoplay-cancel-button:active {
transform: translateY(-1px); transform: translateY(-1px);
box-shadow:
0 4px 15px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
} }
.autoplay-play-button svg, /* Mobile Responsive */
.autoplay-cancel-button svg {
width: 18px;
height: 18px;
flex-shrink: 0;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
transition: transform 0.3s ease;
position: relative;
z-index: 1;
display: block;
margin: 0;
padding: 0;
vertical-align: middle;
}
.autoplay-play-button:hover svg {
transform: scale(1.05);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
}
.autoplay-cancel-button svg {
width: 16px;
height: 16px;
}
.autoplay-cancel-button:hover svg {
transform: scale(1.05) rotate(90deg);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
}
.autoplay-play-button span,
.autoplay-cancel-button span {
display: inline-block;
vertical-align: middle;
line-height: 1;
font-size: inherit;
font-weight: inherit;
letter-spacing: inherit;
text-transform: inherit;
position: relative;
z-index: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
margin: 0;
padding: 0;
height: auto;
align-self: center;
}
/* Ensure perfect alignment of button content */
.autoplay-play-button > *,
.autoplay-cancel-button > * {
vertical-align: middle;
display: inline-block;
}
/* Fix any baseline alignment issues */
.autoplay-play-button,
.autoplay-cancel-button {
align-items: center;
justify-content: center;
}
/* Ensure text and icons are perfectly aligned */
.autoplay-play-button svg,
.autoplay-cancel-button svg {
vertical-align: middle;
display: inline-block;
}
/* Autoplay Toggle Button Styles */
/* .vjs-autoplay-toggle {
width: 3em !important;
height: 3em !important;
flex: none;
padding: 0 !important;
margin: 0 4px !important;
line-height: 3em !important;
position: relative;
} */
/* .vjs-autoplay-toggle .vjs-autoplay-icon {
width: 1.2em;
height: 1.2em;
display: flex;
align-items: center;
justify-content: center;
margin: auto;
} */
.vjs-autoplay-toggle .vjs-autoplay-icon svg {
width: 100%;
height: 100%;
display: block;
}
/* Responsive design */
@media (max-width: 767px) { @media (max-width: 767px) {
.autoplay-countdown-video-info {
margin-bottom: 20px;
}
.autoplay-countdown-content { .autoplay-countdown-content {
padding: 24px; gap: 8px;
max-width: 400px; max-width: 280px;
} }
.autoplay-countdown-header h3 { .countdown-label {
font-size: 20px; font-size: 13px;
} margin: 0;
.next-video-thumbnail {
width: 140px;
height: 78px;
}
.play-overlay {
width: 48px;
height: 48px;
}
.play-overlay svg {
width: 20px;
height: 20px;
} }
.next-video-title { .next-video-title {
font-size: 18px; font-size: 16px;
margin: 0 0 8px 0;
} }
.next-video-author { .next-video-author {
font-size: 14px; font-size: 13px;
margin: -6px 0 0 0;
}
.circular-countdown {
margin: 4px 0;
}
.circular-countdown svg {
width: 80px;
height: 80px;
} }
.autoplay-play-button,
.autoplay-cancel-button { .autoplay-cancel-button {
padding: 12px 24px; padding: 8px 20px;
font-size: 14px; font-size: 12px;
min-width: 120px; margin-top: 4px;
height: 44px;
gap: 6px;
align-items: center;
justify-content: center;
}
.autoplay-play-button svg {
width: 16px;
height: 16px;
vertical-align: middle;
}
.autoplay-cancel-button svg {
width: 14px;
height: 14px;
vertical-align: middle;
} }
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.autoplay-countdown-content { .autoplay-countdown-content {
padding: 20px; gap: 6px;
max-width: 350px; max-width: 260px;
} }
.autoplay-countdown-header h3 { .countdown-label {
font-size: 18px; font-size: 12px;
} margin: 0;
.countdown-timer {
font-size: 24px;
padding: 10px 16px;
}
.autoplay-countdown-video-info {
gap: 16px;
}
.next-video-thumbnail {
width: 120px;
height: 68px;
}
.play-overlay {
width: 40px;
height: 40px;
}
.play-overlay svg {
width: 16px;
height: 16px;
} }
.next-video-title { .next-video-title {
font-size: 16px; font-size: 15px;
margin: 0 0 6px 0;
} }
.next-video-author { .next-video-author {
font-size: 13px; font-size: 12px;
margin: -4px 0 0 0;
} }
.autoplay-countdown-actions { .circular-countdown {
gap: 5px; margin: 2px 0;
padding: 0; }
}
button.autoplay-play-button, .circular-countdown svg {
button.autoplay-cancel-button { width: 70px;
padding: 10px 20px; height: 70px;
width: 120px;
height: 40px;
min-width: 120px;
} }
.autoplay-play-button,
.autoplay-cancel-button { .autoplay-cancel-button {
width: 100%; padding: 6px 16px;
min-width: 100%; font-size: 11px;
height: 46px; margin-top: 2px;
gap: 6px;
padding: 10px 20px;
font-size: 13px;
align-items: center;
justify-content: center;
}
.autoplay-play-button svg {
width: 14px;
height: 14px;
vertical-align: middle;
}
.autoplay-cancel-button svg {
width: 12px;
height: 12px;
vertical-align: middle;
} }
} }

View File

@ -14,7 +14,7 @@ class AutoplayCountdownOverlay extends Component {
this.onCancel = options.onCancel || (() => {}); this.onCancel = options.onCancel || (() => {});
this.currentCountdown = this.countdownSeconds; this.currentCountdown = this.countdownSeconds;
this.countdownInterval = null; this.startTime = null;
this.isActive = false; this.isActive = false;
// Bind methods // Bind methods
@ -32,57 +32,38 @@ class AutoplayCountdownOverlay extends Component {
// Get next video title or fallback // Get next video title or fallback
const nextVideoTitle = this.nextVideoData?.title || 'Next Video'; const nextVideoTitle = this.nextVideoData?.title || 'Next Video';
const nextVideoThumbnail = this.nextVideoData?.thumbnail || '';
overlay.innerHTML = ` overlay.innerHTML = `
<div class="autoplay-countdown-content"> <div class="autoplay-countdown-content">
<div class="autoplay-countdown-header"> <div class="countdown-label">Up Next</div>
<h3>Up next in <span class="countdown-timer">${this.countdownSeconds}</span></h3>
<div class="next-video-title">${nextVideoTitle}</div>
${this.nextVideoData?.author ? `<div class="next-video-author">${this.nextVideoData.author}</div>` : ''}
<div class="circular-countdown">
<svg class="countdown-circle" viewBox="0 0 100 100" width="100" height="100">
<circle cx="50" cy="50" r="45" stroke="rgba(255,255,255,0.2)" stroke-width="3" fill="none"/>
<circle class="countdown-progress" cx="50" cy="50" r="45" stroke="white" stroke-width="3" fill="none"
stroke-dasharray="282.74" stroke-dashoffset="282.74" transform="rotate(-90 50 50)"/>
<g class="play-icon">
<circle cx="50" cy="50" r="20" fill="rgba(255,255,255,0.9)" stroke="none"/>
<path d="M45 40l15 10-15 10z" fill="#000"/>
</g>
</svg>
</div> </div>
<div class="autoplay-countdown-video-info"> <span class="autoplay-cancel-button">
${ CANCEL
nextVideoThumbnail </span>
? `<div class="next-video-thumbnail">
<img src="${nextVideoThumbnail}" alt="${nextVideoTitle}" />
<div class="play-overlay">
<svg viewBox="0 0 24 24" width="28" height="28" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
</div>
</div>`
: ''
}
<div class="next-video-details">
<h4 class="next-video-title">${nextVideoTitle}</h4>
${this.nextVideoData?.author ? `<p class="next-video-author">${this.nextVideoData.author}</p>` : ''}
${this.nextVideoData?.duration ? `<p class="next-video-duration">${this.formatDuration(this.nextVideoData.duration)}</p>` : ''}
</div>
</div>
<div class="autoplay-countdown-actions">
<button class="autoplay-play-button" type="button">
<svg viewBox="0 0 24 24" width="1.2em" height="1.2em" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
Play Now
</button>
<button class="autoplay-cancel-button" type="button">
<svg viewBox="0 0 24 24" width="1.2em" height="1.2em" fill="currentColor">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
Cancel
</button>
</div>
</div> </div>
`; `;
// Add event listeners with explicit binding // Add event listeners with explicit binding
const playButton = overlay.querySelector('.autoplay-play-button'); const circularCountdown = overlay.querySelector('.circular-countdown');
const cancelButton = overlay.querySelector('.autoplay-cancel-button'); const cancelButton = overlay.querySelector('.autoplay-cancel-button');
if (playButton) { if (circularCountdown) {
playButton.addEventListener('click', (e) => { circularCountdown.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
this.handlePlayNext(); this.handlePlayNext();
}); });
@ -104,35 +85,48 @@ class AutoplayCountdownOverlay extends Component {
startCountdown() { startCountdown() {
this.isActive = true; this.isActive = true;
this.currentCountdown = this.countdownSeconds; this.currentCountdown = this.countdownSeconds;
this.startTime = Date.now();
// Show immediately and start countdown without delay
this.show(); this.show();
this.updateCountdownDisplay(); this.updateCountdownDisplay();
// Start countdown interval // Use requestAnimationFrame for smooth animation
this.countdownInterval = setInterval(() => { const animate = () => {
this.currentCountdown--; if (!this.isActive) return;
const elapsed = (Date.now() - this.startTime) / 1000;
this.currentCountdown = Math.max(0, this.countdownSeconds - elapsed);
this.updateCountdownDisplay(); this.updateCountdownDisplay();
if (this.currentCountdown <= 0) { if (this.currentCountdown <= 0) {
this.stopCountdown(); this.stopCountdown();
// Auto-play next video when countdown reaches 0 // Auto-play next video when countdown reaches 0
this.handlePlayNext(); this.handlePlayNext();
} else {
requestAnimationFrame(animate);
} }
}, 1000); };
// Start the animation
requestAnimationFrame(animate);
} }
stopCountdown() { stopCountdown() {
this.isActive = false; this.isActive = false;
if (this.countdownInterval) {
clearInterval(this.countdownInterval);
this.countdownInterval = null;
}
this.hide(); this.hide();
} }
updateCountdownDisplay() { updateCountdownDisplay() {
const timerElement = this.el().querySelector('.countdown-timer'); const progressCircle = this.el().querySelector('.countdown-progress');
if (timerElement) { if (progressCircle) {
timerElement.textContent = this.currentCountdown; // Calculate progress (282.74 is the circumference of the circle with radius 45)
const circumference = 2 * Math.PI * 45; // 282.74
const progress = (this.countdownSeconds - this.currentCountdown) / this.countdownSeconds;
const offset = circumference - circumference * progress;
// Apply the animation
progressCircle.style.strokeDashoffset = offset;
} }
} }
@ -157,9 +151,13 @@ class AutoplayCountdownOverlay extends Component {
show() { show() {
if (this.el()) { if (this.el()) {
this.el().style.display = 'flex'; this.el().style.display = 'flex';
// Add animation class for smooth entrance // Force immediate display and add animation class
requestAnimationFrame(() => {
if (this.el()) {
this.el().classList.add('autoplay-countdown-show'); this.el().classList.add('autoplay-countdown-show');
} }
});
}
} }
hide() { hide() {
@ -190,29 +188,15 @@ class AutoplayCountdownOverlay extends Component {
// Re-render the content if the overlay exists // Re-render the content if the overlay exists
if (this.el()) { if (this.el()) {
const nextVideoTitle = this.nextVideoData?.title || 'Next Video'; const nextVideoTitle = this.nextVideoData?.title || 'Next Video';
const nextVideoThumbnail = this.nextVideoData?.thumbnail || ''; const titleElement = this.el().querySelector('.next-video-title');
const authorElement = this.el().querySelector('.next-video-author');
const videoInfoElement = this.el().querySelector('.autoplay-countdown-video-info'); if (titleElement) {
if (videoInfoElement) { titleElement.textContent = nextVideoTitle;
videoInfoElement.innerHTML = `
${
nextVideoThumbnail
? `<div class="next-video-thumbnail">
<img src="${nextVideoThumbnail}" alt="${nextVideoTitle}" />
<div class="play-overlay">
<svg viewBox="0 0 24 24" width="28" height="28" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
</div>
</div>`
: ''
} }
<div class="next-video-details">
<h4 class="next-video-title">${nextVideoTitle}</h4> if (authorElement && this.nextVideoData?.author) {
${this.nextVideoData?.author ? `<p class="next-video-author">${this.nextVideoData.author}</p>` : ''} authorElement.textContent = this.nextVideoData.author;
${this.nextVideoData?.duration ? `<p class="next-video-duration">${this.formatDuration(this.nextVideoData.duration)}</p>` : ''}
</div>
`;
} }
} }
} }

View File

@ -1046,8 +1046,8 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
}, },
// other // other
useRoundedCorners: true, useRoundedCorners: false,
isPlayList: true, isPlayList: false,
previewSprite: { previewSprite: {
url: 'https://deic.mediacms.io/media/original/thumbnails/user/thorkild/2ca18fadeef8475eae513c12cc0830d3.19990812hd_1920_1080_30fps.mp4sprites.jpg', url: 'https://deic.mediacms.io/media/original/thumbnails/user/thorkild/2ca18fadeef8475eae513c12cc0830d3.19990812hd_1920_1080_30fps.mp4sprites.jpg',
frame: { width: 160, height: 90, seconds: 10 }, frame: { width: 160, height: 90, seconds: 10 },
@ -1685,7 +1685,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
notSupportedMessage: undefined, notSupportedMessage: undefined,
// Prevent title attributes on UI elements for better accessibility // Prevent title attributes on UI elements for better accessibility
noUITitleAttributes: false, noUITitleAttributes: true,
// Array of playback speed options (e.g., [0.5, 1, 1.5, 2]) // Array of playback speed options (e.g., [0.5, 1, 1.5, 2])
playbackRates: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], playbackRates: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],
@ -1834,6 +1834,9 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
// Preload text tracks // Preload text tracks
preloadTextTracks: true, preloadTextTracks: true,
// Play inline
playsinline: true,
}, },
// ===== COMPONENT CONFIGURATION ===== // ===== COMPONENT CONFIGURATION =====
@ -1981,7 +1984,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
handleAutoplay(); handleAutoplay();
} }
const setupMobilePlayPause = () => { /* const setupMobilePlayPause = () => {
const playerEl = playerRef.current.el(); const playerEl = playerRef.current.el();
const videoEl = playerEl.querySelector('video'); const videoEl = playerEl.querySelector('video');
@ -2049,8 +2052,8 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
videoEl.addEventListener('touchstart', handleTouchStart, { passive: true }); videoEl.addEventListener('touchstart', handleTouchStart, { passive: true });
videoEl.addEventListener('touchend', handleTouchEnd, { passive: false }); videoEl.addEventListener('touchend', handleTouchEnd, { passive: false });
} }
}; }; */
setTimeout(setupMobilePlayPause, 100); //setTimeout(setupMobilePlayPause, 100);
// Get control bar and its children // Get control bar and its children
const controlBar = playerRef.current.getChild('controlBar'); const controlBar = playerRef.current.getChild('controlBar');
@ -2526,7 +2529,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
// Store components reference for potential cleanup // Store components reference for potential cleanup
// BEGIN: Fix Android seekbar touch functionality // BEGIN: Fix Android seekbar touch functionality
if (isTouchDevice) { /* if (isTouchDevice) {
setTimeout(() => { setTimeout(() => {
const progressControl = playerRef.current const progressControl = playerRef.current
.getChild('controlBar') .getChild('controlBar')
@ -2616,7 +2619,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
} }
} }
}, 500); }, 500);
} } */
// END: Fix Android seekbar touch functionality // END: Fix Android seekbar touch functionality
// BEGIN: Add comprehensive keyboard event handling // BEGIN: Add comprehensive keyboard event handling
@ -2772,10 +2775,10 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
autoplayCountdown = null; autoplayCountdown = null;
} }
// Show autoplay countdown // Show autoplay countdown immediately
autoplayCountdown = new AutoplayCountdownOverlay(playerRef.current, { autoplayCountdown = new AutoplayCountdownOverlay(playerRef.current, {
nextVideoData: nextVideoData, nextVideoData: nextVideoData,
countdownSeconds: 500, countdownSeconds: 5,
onPlayNext: () => { onPlayNext: () => {
goToNextVideo(); goToNextVideo();
}, },
@ -2790,8 +2793,13 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
}); });
playerRef.current.addChild(autoplayCountdown); playerRef.current.addChild(autoplayCountdown);
// Start countdown immediately without any delay
setTimeout(() => {
if (autoplayCountdown && !autoplayCountdown.isDisposed()) {
autoplayCountdown.startCountdown(); autoplayCountdown.startCountdown();
} }
}, 0);
}
} else { } else {
// Autoplay disabled or no next video - show regular end screen // Autoplay disabled or no next video - show regular end screen
showEndScreen(); showEndScreen();