import { Image } from 'expo-image' import { memo, useEffect, useState } from 'react' import { type ViewStyle } from 'react-native' import Video from 'react-native-video' type Props = { url?: string needWeb?: boolean style?: ViewStyle width?: number } & React.ComponentProps // 默认宽度256半屏宽度 const VideoBox = ({ url, needWeb = true, width = 256, style, ...videoProps }: Props) => { const [urlFinal, setUrlFinal] = useState('') 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 } // 自动从 URL 提取稳定的缓存键 const extractCacheKey = (url: string): string => { try { const urlObj = new URL(url) // 使用路径部分作为缓存键,忽略查询参数(token、签名等) return urlObj.pathname } catch { // URL 解析失败时使用原始 URL return url } } const setRedirectUrl = async (url?: string) => { const isImg2 = isImg(url) if (isImg2) { setUrlFinal(url!) return } const webpUrl = createUrl(url!) const finalUrl = await resolveRedirect(webpUrl) // console.log('setRedirectUrl finalUrl-----------', finalUrl) setUrlFinal(finalUrl!) } useEffect(() => { if (!url) return setRedirectUrl(url!) // const finalUrl = createUrl(url) // console.log('finalUrl-----------', finalUrl) // setUrlFinal(finalUrl) return }, [url]) // console.log('urlFinal--------- ', urlFinal, url) if (!url) return null // 本地文件全部用video组件播放 const isLocal = !url.startsWith('http://') && !url.startsWith('https://') const isImageFile = isImg(url) if (isLocal && !isImageFile) { return (