expo-popcore-app/hooks/use-download-media.ts

72 lines
1.9 KiB
TypeScript

import { useCallback, useState } from 'react'
import * as MediaLibrary from 'expo-media-library'
export type MediaType = 'image' | 'video'
export interface DownloadResult {
success: boolean
error?: string
}
// 使用 fetch 下载文件并转换为 base64
const downloadToCache = async (url: string, fileName: string): Promise<string> => {
const response = await fetch(url)
if (!response.ok) {
throw new Error('Download failed')
}
const blob = await response.blob()
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => {
const base64data = reader.result as string
resolve(base64data)
}
reader.onerror = reject
reader.readAsDataURL(blob)
})
}
export const useDownloadMedia = () => {
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [progress, setProgress] = useState(0)
const download = useCallback(async (url: string, type: MediaType): Promise<DownloadResult> => {
setLoading(true)
setError(null)
setProgress(0)
try {
// 1. 请求媒体库权限
const { status } = await MediaLibrary.requestPermissionsAsync()
if (status !== 'granted') {
setError('Permission denied')
setLoading(false)
return { success: false, error: 'Permission denied' }
}
setProgress(0.3)
// 2. 使用 MediaLibrary.saveToLibraryAsync 直接从 URL 保存
// 这个方法可以直接接受远程 URL
await MediaLibrary.saveToLibraryAsync(url)
setProgress(1)
setLoading(false)
setProgress(0)
return { success: true }
} catch (e) {
const errorMessage = e instanceof Error ? e.message : 'Download failed'
setError(errorMessage)
setLoading(false)
setProgress(0)
return { success: false, error: errorMessage }
}
}, [])
return { download, loading, error, progress }
}