From 44a669b6fca4e99d422c63039c9dfcf89fa95ef2 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 11 Jul 2025 11:39:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=96=87=E4=BB=B6=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=AD=98=E5=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/file_utils.rs | 33 ++++++++++ src-tauri/src/lib.rs | 4 +- src-tauri/tauri.conf.json | 2 +- src/components/VideoPlayer.tsx | 90 +++++++++++++++++++++++----- 4 files changed, 111 insertions(+), 18 deletions(-) diff --git a/src-tauri/src/commands/file_utils.rs b/src-tauri/src/commands/file_utils.rs index 556388c..a65ffde 100644 --- a/src-tauri/src/commands/file_utils.rs +++ b/src-tauri/src/commands/file_utils.rs @@ -81,6 +81,39 @@ pub async fn read_video_as_data_url(file_path: String) -> Result } } +/// 检查文件是否存在 +#[command] +pub async fn check_file_exists(file_path: String) -> Result { + let path = Path::new(&file_path); + Ok(path.exists()) +} + +/// 获取文件信息 +#[command] +pub async fn get_file_info(file_path: String) -> Result { + 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 { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7aa52a7..13a978d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -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"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 586f683..7ec51b7 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -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": ["**"] diff --git a/src/components/VideoPlayer.tsx b/src/components/VideoPlayer.tsx index 9f627f2..134da03 100644 --- a/src/components/VideoPlayer.tsx +++ b/src/components/VideoPlayer.tsx @@ -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 = ({ const [volume, setVolume] = useState(1) const [isFullscreen, setIsFullscreen] = useState(false) const [videoSrc, setVideoSrc] = useState('') + const [fileExists, setFileExists] = useState(true) + const [errorMessage, setErrorMessage] = useState('') useEffect(() => { - if (isOpen && videoPath) { - // 使用Tauri的convertFileSrc来获取安全的文件URL - const src = convertFileSrc(videoPath) - console.log({ src }) - setVideoSrc(src) + const checkFileAndSetSrc = async () => { + if (isOpen && videoPath) { + try { + // 首先检查文件是否存在 + const exists = await invoke('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 = ({ {/* 视频容器 */}
-