fix: Show autoplay button everywhere, Remove fake related items, Trim audio on Safari (#1424)

This commit is contained in:
Yiannis Christodoulou 2025-11-04 09:38:39 +02:00 committed by GitHub
parent 3e79f5a558
commit fef262496d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 216 additions and 353 deletions

View File

@ -47,14 +47,24 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
const isValidPoster = mediaPosterUrl && mediaPosterUrl !== 'None' && mediaPosterUrl.trim() !== ''; const isValidPoster = mediaPosterUrl && mediaPosterUrl !== 'None' && mediaPosterUrl.trim() !== '';
const posterImage = isValidPoster ? mediaPosterUrl : (isAudioFile ? AUDIO_POSTER_URL : undefined); const posterImage = isValidPoster ? mediaPosterUrl : (isAudioFile ? AUDIO_POSTER_URL : undefined);
// Detect iOS device // Detect iOS device and Safari browser
useEffect(() => { useEffect(() => {
const checkIOS = () => { const checkIOS = () => {
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera; const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera;
return /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream; return /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream;
}; };
const checkSafari = () => {
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera;
return /Safari/.test(userAgent) && !/Chrome/.test(userAgent) && !/Chromium/.test(userAgent);
};
setIsIOS(checkIOS()); setIsIOS(checkIOS());
// Store Safari detection globally for other components
if (typeof window !== 'undefined') {
(window as any).isSafari = checkSafari();
}
// Check if video was previously initialized // Check if video was previously initialized
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
@ -345,7 +355,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
<div className="video-player-container"> <div className="video-player-container">
<video <video
ref={videoRef} ref={videoRef}
preload="auto" preload="metadata"
crossOrigin="anonymous" crossOrigin="anonymous"
onClick={handleVideoClick} onClick={handleVideoClick}
playsInline playsInline
@ -356,7 +366,10 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
poster={posterImage} poster={posterImage}
> >
<source src={sampleVideoUrl} type="video/mp4" /> <source src={sampleVideoUrl} type="video/mp4" />
<p>Your browser doesn't support HTML5 video.</p> {/* Safari fallback for audio files */}
<source src={sampleVideoUrl} type="audio/mp4" />
<source src={sampleVideoUrl} type="audio/mpeg" />
<p>Your browser doesn't support HTML5 video or audio.</p>
</video> </video>
{/* iOS First-play indicator - only shown on first visit for iOS devices when not initialized */} {/* iOS First-play indicator - only shown on first visit for iOS devices when not initialized */}

View File

@ -49,10 +49,7 @@ class EndScreenOverlay extends Component {
// Get videos to show - access directly from options during createEl // Get videos to show - access directly from options during createEl
const relatedVideos = this.options_?.relatedVideos || this.relatedVideos || []; const relatedVideos = this.options_?.relatedVideos || this.relatedVideos || [];
const videosToShow = const videosToShow = relatedVideos.slice(0, maxVideos);
relatedVideos.length > 0
? relatedVideos.slice(0, maxVideos)
: this.createSampleVideos().slice(0, maxVideos);
if (useSwiper) { if (useSwiper) {
return this.createSwiperGrid(videosToShow, itemsPerView || 2, columns, gridRows || 1); return this.createSwiperGrid(videosToShow, itemsPerView || 2, columns, gridRows || 1);
@ -307,8 +304,8 @@ class EndScreenOverlay extends Component {
if (this.relatedVideos && Array.isArray(this.relatedVideos) && this.relatedVideos.length > 0) { if (this.relatedVideos && Array.isArray(this.relatedVideos) && this.relatedVideos.length > 0) {
return this.relatedVideos.slice(0, maxVideos); return this.relatedVideos.slice(0, maxVideos);
} }
// Fallback to sample videos for testing // Return empty array if no related videos
return this.createSampleVideos().slice(0, maxVideos); return [];
} }
createVideoItem(video, isSwiperMode = false, itemsPerView = 2, isGridMode = false) { createVideoItem(video, isSwiperMode = false, itemsPerView = 2, isGridMode = false) {
@ -745,153 +742,12 @@ class EndScreenOverlay extends Component {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0; return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
} }
createSampleVideos() {
return [
{
id: 'sample1',
title: 'React Full Course - Complete Tutorial for Beginners',
author: 'Bro Code',
views: '2.1M views',
duration: 1800,
},
{
id: 'sample2',
title: 'JavaScript ES6+ Modern Features',
author: 'Tech Tutorials',
views: '850K views',
duration: 1200,
},
{
id: 'sample3',
title: 'CSS Grid Layout Masterclass',
author: 'Web Dev Academy',
views: '1.2M views',
duration: 2400,
},
{
id: 'sample4',
title: 'Node.js Backend Development',
author: 'Code Master',
views: '650K views',
duration: 3600,
},
{
id: 'sample5',
title: 'Vue.js Complete Guide',
author: 'Frontend Pro',
views: '980K views',
duration: 2800,
},
{
id: 'sample6',
title: 'Python Data Science Bootcamp',
author: 'Data Academy',
views: '1.5M views',
duration: 4200,
},
{
id: 'sample7',
title: 'TypeScript for Beginners',
author: 'Code School',
views: '750K views',
duration: 1950,
},
{
id: 'sample8',
title: 'Docker Container Tutorial',
author: 'DevOps Pro',
views: '920K views',
duration: 2700,
},
{
id: 'sample9',
title: 'MongoDB Database Design',
author: 'DB Expert',
views: '580K views',
duration: 3200,
},
{
id: 'sample10',
title: 'AWS Cloud Computing Essentials',
author: 'Cloud Master',
views: '1.8M views',
duration: 4800,
},
{
id: 'sample11',
title: 'GraphQL API Development',
author: 'API Guru',
views: '420K views',
duration: 2100,
},
{
id: 'sample12',
title: 'Kubernetes Orchestration Guide',
author: 'Container Pro',
views: '680K views',
duration: 3900,
},
{
id: 'sample13',
title: 'Redis Caching Strategies',
author: 'Cache Expert',
views: '520K views',
duration: 2250,
},
{
id: 'sample14',
title: 'Web Performance Optimization',
author: 'Speed Master',
views: '890K views',
duration: 3100,
},
{
id: 'sample15',
title: 'CI/CD Pipeline Setup',
author: 'DevOps Guide',
views: '710K views',
duration: 2900,
},
{
id: 'sample16',
title: 'Microservices Architecture',
author: 'System Design',
views: '1.3M views',
duration: 4500,
},
{
id: 'sample17',
title: 'Next.js App Router Tutorial',
author: 'Web Academy',
views: '640K views',
duration: 2650,
},
{
id: 'sample18',
title: 'Tailwind CSS Crash Course',
author: 'CSS Master',
views: '1.1M views',
duration: 1800,
},
{
id: 'sample19',
title: 'Git and GitHub Essentials',
author: 'Version Control Pro',
views: '2.3M views',
duration: 3300,
},
{
id: 'sample20',
title: 'REST API Best Practices',
author: 'API Design',
views: '780K views',
duration: 2400,
},
];
}
show() { show() {
this.el().style.display = 'flex'; // Only show if there are related videos
const relatedVideos = this.options_?.relatedVideos || this.relatedVideos || [];
if (relatedVideos.length > 0) {
this.el().style.display = 'flex';
}
} }
hide() { hide() {

View File

@ -139,12 +139,6 @@ video::cue {
} }
} }
@media (max-width: 600px) {
.video-js .vjs-control-bar .vjs-autoplay-toggle {
display: none !important;
}
}
@media (max-width: 500px) { @media (max-width: 500px) {
.video-js .vjs-control-bar .vjs-next-video-button { .video-js .vjs-control-bar .vjs-next-video-button {
display: none !important; display: none !important;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long