Improve video preview by adding HLS support for smoother playback
Integrate HLS.js into the video card component to enable adaptive streaming for video previews, enhancing the user experience by ensuring smoother playback across different network conditions. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 2eb1084e-b728-4449-9231-f1665924c8d5 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2eb1084e-b728-4449-9231-f1665924c8d5/P3O2FU7
This commit is contained in:
parent
e0a01aa0b5
commit
50cc4a1346
@ -2,6 +2,8 @@ import { Play } from "lucide-react";
|
||||
import { type Video } from "@shared/schema";
|
||||
import HLSPreviewThumbnail from "./hls-preview-thumbnail";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
// @ts-ignore
|
||||
import Hls from 'hls.js';
|
||||
|
||||
interface VideoCardProps {
|
||||
video: Video;
|
||||
@ -46,6 +48,8 @@ export default function VideoCard({ video, onClick, className = "" }: VideoCardP
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [showPreview, setShowPreview] = useState(false);
|
||||
const hoverTimeoutRef = useRef<NodeJS.Timeout>();
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const hlsRef = useRef<any>(null);
|
||||
|
||||
// Delay preview start to avoid loading on quick mouse passes
|
||||
useEffect(() => {
|
||||
@ -67,6 +71,52 @@ export default function VideoCard({ video, onClick, className = "" }: VideoCardP
|
||||
};
|
||||
}, [isHovered]);
|
||||
|
||||
// Setup HLS when preview is shown
|
||||
useEffect(() => {
|
||||
if (showPreview && videoRef.current && video.videoUrl) {
|
||||
const videoElement = videoRef.current;
|
||||
|
||||
if (Hls.isSupported()) {
|
||||
console.log('Setting up HLS preview for:', video.title);
|
||||
hlsRef.current = new Hls({
|
||||
enableWorker: false,
|
||||
lowLatencyMode: false,
|
||||
backBufferLength: 30,
|
||||
maxBufferLength: 60,
|
||||
maxMaxBufferLength: 120,
|
||||
maxBufferSize: 60 * 1000 * 1000,
|
||||
maxBufferHole: 0.5,
|
||||
startLevel: 0,
|
||||
autoStartLoad: true,
|
||||
debug: false,
|
||||
});
|
||||
|
||||
hlsRef.current.loadSource(video.videoUrl);
|
||||
hlsRef.current.attachMedia(videoElement);
|
||||
|
||||
hlsRef.current.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
console.log('HLS manifest parsed, starting playback');
|
||||
videoElement.play().catch(e => console.log('Autoplay failed:', e));
|
||||
});
|
||||
|
||||
hlsRef.current.on(Hls.Events.ERROR, (event: any, data: any) => {
|
||||
console.log('HLS error:', data);
|
||||
});
|
||||
} else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
// Safari native HLS support
|
||||
videoElement.src = video.videoUrl;
|
||||
videoElement.play().catch(e => console.log('Autoplay failed:', e));
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (hlsRef.current) {
|
||||
hlsRef.current.destroy();
|
||||
hlsRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [showPreview, video.videoUrl]);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid={`card-video-${video.id}`}
|
||||
@ -111,29 +161,17 @@ export default function VideoCard({ video, onClick, className = "" }: VideoCardP
|
||||
{showPreview && (
|
||||
<div className="absolute inset-0">
|
||||
<video
|
||||
ref={videoRef}
|
||||
className="w-full h-full object-cover"
|
||||
style={{
|
||||
objectPosition: video.faceCenterPosition || 'center center',
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="none"
|
||||
onLoadStart={() => console.log('Preview loading for:', video.title)}
|
||||
onError={(e) => console.log('Preview failed for:', video.title)}
|
||||
onCanPlay={() => console.log('Preview ready for:', video.title)}
|
||||
>
|
||||
{/* Try MP4 source first for faster loading */}
|
||||
{video.videoUrlMp4 && (
|
||||
<source src={video.videoUrlMp4} type="video/mp4" />
|
||||
)}
|
||||
{/* Fallback to HLS if MP4 fails */}
|
||||
{video.videoUrl && (
|
||||
<source src={video.videoUrl} type="application/x-mpegURL" />
|
||||
)}
|
||||
</video>
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user