检查文件是否存在
This commit is contained in:
parent
47b156c68a
commit
44a669b6fc
|
|
@ -81,6 +81,39 @@ pub async fn read_video_as_data_url(file_path: String) -> Result<String, String>
|
|||
}
|
||||
}
|
||||
|
||||
/// 检查文件是否存在
|
||||
#[command]
|
||||
pub async fn check_file_exists(file_path: String) -> Result<bool, String> {
|
||||
let path = Path::new(&file_path);
|
||||
Ok(path.exists())
|
||||
}
|
||||
|
||||
/// 获取文件信息
|
||||
#[command]
|
||||
pub async fn get_file_info(file_path: String) -> Result<serde_json::Value, String> {
|
||||
let path = Path::new(&file_path);
|
||||
|
||||
if !path.exists() {
|
||||
return Err("File does not exist".to_string());
|
||||
}
|
||||
|
||||
match fs::metadata(&file_path) {
|
||||
Ok(metadata) => {
|
||||
let info = serde_json::json!({
|
||||
"exists": true,
|
||||
"size": metadata.len(),
|
||||
"is_file": metadata.is_file(),
|
||||
"is_dir": metadata.is_dir(),
|
||||
"modified": metadata.modified()
|
||||
.map(|t| t.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs())
|
||||
.unwrap_or(0)
|
||||
});
|
||||
Ok(info)
|
||||
}
|
||||
Err(e) => Err(format!("Failed to get file metadata: {}", e))
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取视频文件的blob URL(用于大文件)
|
||||
#[command]
|
||||
pub async fn get_video_blob_url(file_path: String) -> Result<String, String> {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ pub fn run() {
|
|||
commands::media::delete_original_video,
|
||||
commands::file_utils::read_image_as_data_url,
|
||||
commands::file_utils::read_video_as_data_url,
|
||||
commands::file_utils::get_video_blob_url
|
||||
commands::file_utils::get_video_blob_url,
|
||||
commands::file_utils::check_file_exists,
|
||||
commands::file_utils::get_file_info
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost data:; media-src 'self' asset: http://asset.localhost; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
|
||||
"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost data:; media-src 'self' asset: http://asset.localhost; video-src 'self' asset: http://asset.localhost; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
|
||||
"assetProtocol": {
|
||||
"enable": true,
|
||||
"scope": ["**"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useRef, useEffect } from 'react'
|
||||
import { Play, Pause, Volume2, VolumeX, Maximize2, X } from 'lucide-react'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { Play, Pause, Volume2, VolumeX, Maximize2, X, AlertCircle } from 'lucide-react'
|
||||
import { convertFileSrc, invoke } from '@tauri-apps/api/core'
|
||||
|
||||
interface VideoPlayerProps {
|
||||
videoPath: string
|
||||
|
|
@ -23,14 +23,43 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
const [volume, setVolume] = useState(1)
|
||||
const [isFullscreen, setIsFullscreen] = useState(false)
|
||||
const [videoSrc, setVideoSrc] = useState<string>('')
|
||||
const [fileExists, setFileExists] = useState<boolean>(true)
|
||||
const [errorMessage, setErrorMessage] = useState<string>('')
|
||||
|
||||
useEffect(() => {
|
||||
const checkFileAndSetSrc = async () => {
|
||||
if (isOpen && videoPath) {
|
||||
// 使用Tauri的convertFileSrc来获取安全的文件URL
|
||||
const src = convertFileSrc(videoPath)
|
||||
console.log({ src })
|
||||
setVideoSrc(src)
|
||||
try {
|
||||
// 首先检查文件是否存在
|
||||
const exists = await invoke<boolean>('check_file_exists', { filePath: videoPath })
|
||||
console.log('File exists check:', { videoPath, exists })
|
||||
|
||||
if (!exists) {
|
||||
setFileExists(false)
|
||||
setErrorMessage(`文件不存在: ${videoPath}`)
|
||||
return
|
||||
}
|
||||
|
||||
// 文件存在,转换为安全URL
|
||||
const src = convertFileSrc(videoPath)
|
||||
console.log('Video path conversion:', {
|
||||
originalPath: videoPath,
|
||||
convertedSrc: src,
|
||||
fileExists: exists
|
||||
})
|
||||
|
||||
setFileExists(true)
|
||||
setErrorMessage('')
|
||||
setVideoSrc(src)
|
||||
} catch (error) {
|
||||
console.error('Error checking file:', error)
|
||||
setFileExists(false)
|
||||
setErrorMessage(`文件检查失败: ${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkFileAndSetSrc()
|
||||
}, [isOpen, videoPath])
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -146,15 +175,44 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
|
||||
{/* 视频容器 */}
|
||||
<div className="relative bg-black rounded-lg overflow-hidden">
|
||||
{!fileExists || errorMessage ? (
|
||||
/* 错误显示 */
|
||||
<div className="flex items-center justify-center h-96 text-white">
|
||||
<div className="text-center">
|
||||
<AlertCircle size={64} className="mx-auto mb-4 text-red-400" />
|
||||
<h3 className="text-xl font-medium mb-2">视频加载失败</h3>
|
||||
<p className="text-gray-300 mb-4">{errorMessage}</p>
|
||||
<p className="text-sm text-gray-400">文件路径: {videoPath}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<video
|
||||
ref={videoRef}
|
||||
src={videoSrc}
|
||||
className="w-full h-auto max-h-[70vh]"
|
||||
onClick={handlePlayPause}
|
||||
onError={(e) => {
|
||||
console.error('Video error:', e)
|
||||
console.error('Video loading error:', {
|
||||
error: e,
|
||||
videoSrc,
|
||||
originalPath: videoPath,
|
||||
currentTarget: e.currentTarget,
|
||||
networkState: e.currentTarget.networkState,
|
||||
readyState: e.currentTarget.readyState
|
||||
})
|
||||
setErrorMessage('视频加载失败,请检查文件格式和路径')
|
||||
}}
|
||||
onLoadStart={() => {
|
||||
console.log('Video load started:', videoSrc)
|
||||
}}
|
||||
onCanPlay={() => {
|
||||
console.log('Video can play:', videoSrc)
|
||||
}}
|
||||
onLoadedData={() => {
|
||||
console.log('Video data loaded:', videoSrc)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 控制栏 */}
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-4">
|
||||
|
|
|
|||
Loading…
Reference in New Issue