2025-06-03 00:44:35 +08:00
|
|
|
import React, { useContext, useState, useRef, useEffect } from 'react';
|
|
|
|
import { useParams, useNavigate } from 'react-router-dom';
|
2023-07-04 23:47:01 +08:00
|
|
|
import Container from '@mui/material/Container';
|
|
|
|
import Typography from '@mui/material/Typography';
|
2025-06-03 00:44:35 +08:00
|
|
|
import Box from '@mui/material/Box';
|
|
|
|
import IconButton from '@mui/material/IconButton';
|
|
|
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
2023-07-09 05:58:33 +08:00
|
|
|
import ConfigContext from '../Config';
|
2024-03-28 03:34:50 +08:00
|
|
|
import ReactPlayer from 'react-player';
|
|
|
|
|
2023-07-04 23:47:01 +08:00
|
|
|
const VideoPlayer = () => {
|
2023-07-08 03:15:48 +08:00
|
|
|
const config = useContext(ConfigContext);
|
2023-07-04 23:47:01 +08:00
|
|
|
const { filename } = useParams();
|
2025-06-03 00:44:35 +08:00
|
|
|
const navigate = useNavigate();
|
|
|
|
const playerRef = useRef(null);
|
|
|
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const [error, setError] = useState(null);
|
|
|
|
const [isMobile, setIsMobile] = useState(false);
|
|
|
|
|
|
|
|
// 检测移动设备
|
|
|
|
useEffect(() => {
|
|
|
|
const checkMobile = () => {
|
|
|
|
setIsMobile(window.innerWidth <= 768);
|
|
|
|
};
|
|
|
|
|
|
|
|
checkMobile();
|
|
|
|
window.addEventListener('resize', checkMobile);
|
|
|
|
return () => window.removeEventListener('resize', checkMobile);
|
|
|
|
}, []);
|
2023-07-04 23:47:01 +08:00
|
|
|
|
2025-06-03 00:44:35 +08:00
|
|
|
// 解码文件名
|
|
|
|
const decodedFilename = decodeURIComponent(filename);
|
|
|
|
const videoUrl = `${window.location.origin}/res/${filename}`;
|
2024-03-28 03:34:50 +08:00
|
|
|
|
2025-06-03 00:44:35 +08:00
|
|
|
const handleReady = () => {
|
|
|
|
setLoading(false);
|
2024-03-28 03:34:50 +08:00
|
|
|
};
|
|
|
|
|
2025-06-03 00:44:35 +08:00
|
|
|
const handleError = (error) => {
|
|
|
|
console.error('Video error:', error);
|
|
|
|
setError('视频加载失败');
|
|
|
|
setLoading(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
// 错误页面
|
|
|
|
if (error) {
|
|
|
|
return (
|
|
|
|
<Container sx={{ mt: 2 }}>
|
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
|
|
|
<IconButton onClick={() => navigate(-1)} sx={{ mr: 1 }}>
|
|
|
|
<ArrowBackIcon />
|
|
|
|
</IconButton>
|
|
|
|
<Typography variant="h6" noWrap>
|
|
|
|
{decodedFilename}
|
|
|
|
</Typography>
|
|
|
|
</Box>
|
|
|
|
<Box sx={{ textAlign: 'center', p: 4 }}>
|
|
|
|
<Typography color="error">{error}</Typography>
|
|
|
|
</Box>
|
|
|
|
</Container>
|
|
|
|
);
|
|
|
|
}
|
2024-03-28 03:34:50 +08:00
|
|
|
|
2023-07-04 23:47:01 +08:00
|
|
|
return (
|
2025-06-03 00:44:35 +08:00
|
|
|
<Box sx={{
|
|
|
|
bgcolor: 'black',
|
|
|
|
minHeight: '100vh',
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column'
|
|
|
|
}}>
|
|
|
|
{/* 标题栏 */}
|
|
|
|
<Box sx={{
|
|
|
|
p: isMobile ? 1 : 2,
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
|
|
|
bgcolor: 'rgba(0,0,0,0.8)',
|
|
|
|
color: 'white',
|
|
|
|
position: 'sticky',
|
|
|
|
top: 0,
|
|
|
|
zIndex: 1
|
|
|
|
}}>
|
|
|
|
<IconButton
|
|
|
|
onClick={() => navigate(-1)}
|
|
|
|
sx={{ color: 'white', mr: 1 }}
|
|
|
|
size={isMobile ? 'small' : 'medium'}
|
|
|
|
>
|
|
|
|
<ArrowBackIcon />
|
|
|
|
</IconButton>
|
|
|
|
<Typography
|
|
|
|
variant={isMobile ? 'subtitle1' : 'h6'}
|
|
|
|
noWrap
|
|
|
|
sx={{ flexGrow: 1 }}
|
|
|
|
>
|
|
|
|
{decodedFilename}
|
|
|
|
</Typography>
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
{/* 视频播放器容器 */}
|
|
|
|
<Box sx={{
|
|
|
|
flexGrow: 1,
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
|
|
|
justifyContent: 'center',
|
|
|
|
position: 'relative'
|
|
|
|
}}>
|
|
|
|
{loading && (
|
|
|
|
<Typography sx={{ color: 'white', position: 'absolute' }}>
|
|
|
|
加载中...
|
|
|
|
</Typography>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<ReactPlayer
|
|
|
|
ref={playerRef}
|
|
|
|
url={videoUrl}
|
|
|
|
controls
|
|
|
|
width="100%"
|
|
|
|
height={isMobile ? "50vh" : "70vh"}
|
|
|
|
onReady={handleReady}
|
|
|
|
onError={handleError}
|
|
|
|
config={{
|
|
|
|
file: {
|
|
|
|
attributes: {
|
|
|
|
playsInline: true, // 重要:移动端内联播放
|
2025-08-14 00:28:29 +08:00
|
|
|
preload: 'metadata',
|
|
|
|
disablePictureInPicture: true // 禁用画中画模式
|
2025-06-03 00:44:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
style={{
|
|
|
|
maxWidth: '100%',
|
2025-08-14 00:28:29 +08:00
|
|
|
maxHeight: '100%',
|
|
|
|
margin: 'auto' // 居中显示
|
2025-06-03 00:44:35 +08:00
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Box>
|
|
|
|
|
2025-08-14 00:28:29 +08:00
|
|
|
{/* 底部信息(移动端显示简化提示) */}
|
|
|
|
<Box sx={{
|
|
|
|
p: isMobile ? 1 : 2,
|
|
|
|
color: 'rgba(255,255,255,0.7)',
|
|
|
|
textAlign: 'center',
|
|
|
|
fontSize: '0.8rem'
|
|
|
|
}}>
|
|
|
|
<Typography variant="caption">
|
|
|
|
{isMobile ? '双击可全屏' : '提示:双击视频可全屏播放'}
|
|
|
|
</Typography>
|
|
|
|
</Box>
|
2025-06-03 00:44:35 +08:00
|
|
|
</Box>
|
2023-07-04 23:47:01 +08:00
|
|
|
);
|
|
|
|
};
|
2025-06-03 00:44:35 +08:00
|
|
|
|
2023-07-04 23:47:01 +08:00
|
|
|
export default VideoPlayer;
|