Files
smesh/src/components/MediaPlayer/index.tsx
codytseng 206cbf7e19 feat: 💨
2025-09-13 23:36:49 +08:00

89 lines
2.0 KiB
TypeScript

import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AudioPlayer from '../AudioPlayer'
import VideoPlayer from '../VideoPlayer'
export default function MediaPlayer({
src,
className,
mustLoad = false
}: {
src: string
className?: string
mustLoad?: boolean
}) {
const { t } = useTranslation()
const { autoLoadMedia } = useContentPolicy()
const [display, setDisplay] = useState(autoLoadMedia)
const [mediaType, setMediaType] = useState<'video' | 'audio' | null>(null)
useEffect(() => {
if (autoLoadMedia) {
setDisplay(true)
} else {
setDisplay(false)
}
}, [autoLoadMedia])
useEffect(() => {
if (!mustLoad && !display) {
setMediaType(null)
return
}
if (!src) {
setMediaType(null)
return
}
const url = new URL(src)
const extension = url.pathname.split('.').pop()?.toLowerCase()
if (extension && ['mp3', 'wav', 'flac', 'aac', 'm4a', 'opus', 'wma'].includes(extension)) {
setMediaType('audio')
return
}
const video = document.createElement('video')
video.src = src
video.preload = 'metadata'
video.crossOrigin = 'anonymous'
video.onloadedmetadata = () => {
setMediaType(video.videoWidth > 0 || video.videoHeight > 0 ? 'video' : 'audio')
}
video.onerror = () => {
setMediaType(null)
}
return () => {
video.src = ''
}
}, [src, display, mustLoad])
if (!mustLoad && !display) {
return (
<div
className="text-primary hover:underline truncate w-fit cursor-pointer"
onClick={(e) => {
e.stopPropagation()
setDisplay(true)
}}
>
[{t('Click to load media')}]
</div>
)
}
if (!mediaType) {
return null
}
if (mediaType === 'video') {
return <VideoPlayer src={src} className={className} />
}
return <AudioPlayer src={src} className={className} />
}