import { Image, type ImageRef } from 'expo-image' import { memo, useEffect, useRef, useState } from 'react' import { type ViewStyle } from 'react-native' import Video from 'react-native-video' import { videoUrlCache } from '@/utils/storage' type Props = { url?: string needWeb?: boolean style?: ViewStyle width?: number autoplay?: boolean // 控制动画播放,默认 true } & React.ComponentProps // 默认宽度256半屏宽度 const VideoBox = ({ url, needWeb = true, width = 256, style, autoplay = true, ...videoProps }: Props) => { const [urlFinal, setUrlFinal] = useState('') const imageRef = useRef(null) const createUrl = (url: string) => { return `https://modal-dev.bowong.cc/api/custom/video/converter/v2?media_url=${encodeURI(url)}&options=compression_level=3,quality=70,loop=true,resolution=${width}x${width},fps=24` } const isImg = (url: any) => { if (!url) return false const lowerUrl = url.toLowerCase() return lowerUrl?.match(/\.(jpg|jpeg|png|gif|webp|bmp|tiff|svg)(\?.*)?$/i) } async function resolveRedirect(url: string) { const res = await fetch(url, { method: 'GET', headers: { Range: 'bytes=0-0', }, }) return res.url } const setRedirectUrl = async (url?: string) => { const isImg2 = isImg(url) if (isImg2) { setUrlFinal(url!) return } try { // 先尝试从缓存获取 const cachedUrl = await videoUrlCache.get(url!, width) // console.log('getRedirectUrl cachedUrl-----------', url, cachedUrl, width) if (cachedUrl) { setUrlFinal(cachedUrl) return } // 缓存未命中,进行网络请求 const webpUrl = createUrl(url!) const finalUrl = await resolveRedirect(webpUrl) // 缓存结果 await videoUrlCache.set(url!, finalUrl, width) // console.log('setRedirectUrl finalUrl-----------', finalUrl) setUrlFinal(finalUrl!) } catch (error) { console.warn('获取视频URL失败:', error) // 错误时尝试使用原始URL setUrlFinal(url!) } } useEffect(() => { if (!url) return setRedirectUrl(url!) // const finalUrl = createUrl(url) return }, [url]) // 控制动画播放/停止 useEffect(() => { if (imageRef.current) { if (autoplay) { imageRef.current?.startAnimating() } else { imageRef.current?.stopAnimating() } } }, [autoplay]) if (!url) return null // 本地文件全部用video组件播放 const isLocal = !url.startsWith('http://') && !url.startsWith('https://') const isImageFile = isImg(url) if (isLocal) { if (!isImageFile) { return (