refactor: Update VideoCard to handle video playing state

This commit is contained in:
Peifan Li
2025-12-01 18:00:26 -05:00
parent d27be1a268
commit 3da6bdcfdd
2 changed files with 29 additions and 22 deletions

View File

@@ -44,6 +44,7 @@ const VideoCard: React.FC<VideoCardProps> = ({
const [isDeleting, setIsDeleting] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [isHovered, setIsHovered] = useState(false);
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
// Helper to parse duration to seconds
@@ -72,6 +73,7 @@ const VideoCard: React.FC<VideoCardProps> = ({
const handleMouseLeave = () => {
setIsHovered(false);
setIsVideoPlaying(false);
};
// Format the date (assuming format YYYYMMDD from youtube-dl)
@@ -195,27 +197,6 @@ const VideoCard: React.FC<VideoCardProps> = ({
sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', alignItems: 'stretch' }}
>
<Box sx={{ position: 'relative', paddingTop: '56.25%' /* 16:9 aspect ratio */ }}>
<CardMedia
component="img"
image={thumbnailSrc || 'https://via.placeholder.com/480x360?text=No+Thumbnail'}
alt={`${video.title} thumbnail`}
sx={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
opacity: isHovered ? 0 : 1,
transition: 'opacity 0.2s'
}}
onError={(e) => {
const target = e.target as HTMLImageElement;
target.onerror = null;
target.src = 'https://via.placeholder.com/480x360?text=No+Thumbnail';
}}
/>
{isHovered && video.videoPath && (
<Box
component="video"
@@ -224,6 +205,7 @@ const VideoCard: React.FC<VideoCardProps> = ({
muted
autoPlay
playsInline
onPlaying={() => setIsVideoPlaying(true)}
sx={{
position: 'absolute',
top: 0,
@@ -254,6 +236,28 @@ const VideoCard: React.FC<VideoCardProps> = ({
/>
)}
<CardMedia
component="img"
image={thumbnailSrc || 'https://via.placeholder.com/480x360?text=No+Thumbnail'}
alt={`${video.title} thumbnail`}
sx={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
opacity: (isHovered && isVideoPlaying) ? 0 : 1,
transition: 'opacity 0.2s',
pointerEvents: 'none' // Ensure hover events pass through to the video if needed, though parent handles it
}}
onError={(e) => {
const target = e.target as HTMLImageElement;
target.onerror = null;
target.src = 'https://via.placeholder.com/480x360?text=No+Thumbnail';
}}
/>
{video.partNumber && video.totalParts && video.totalParts > 1 && (

View File

@@ -60,6 +60,7 @@ const Home: React.FC = () => {
return (saved as 'collections' | 'all-videos') || 'collections';
});
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
const [settingsLoaded, setSettingsLoaded] = useState(false);
// Fetch settings on mount
useEffect(() => {
@@ -71,6 +72,8 @@ const Home: React.FC = () => {
}
} catch (error) {
console.error('Failed to fetch settings:', error);
} finally {
setSettingsLoaded(true);
}
};
fetchSettings();
@@ -121,7 +124,7 @@ const Home: React.FC = () => {
// Add default empty array to ensure videos is always an array
const videoArray = Array.isArray(videos) ? videos : [];
if (loading && videoArray.length === 0 && !isSearchMode) {
if (!settingsLoaded || (loading && videoArray.length === 0 && !isSearchMode)) {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '50vh' }}>
<CircularProgress />