可以正常播放

This commit is contained in:
2025-08-17 22:20:39 +08:00
parent 90e4a01e62
commit a02c37277e
2 changed files with 100 additions and 61 deletions

View File

@@ -114,17 +114,20 @@ async function updateVideoSrc() {
return return
} }
const filePath = raw.startsWith('file://') ? raw.slice(7) : raw // Always use HTTP protocol for both Tauri and development
console.log('🎥 Converting video path:', { raw, filePath }) // This works reliably in both environments
const filename = raw.split('/').pop() || 'video.mp4'
// Use file:// protocol for local files in Tauri // Use relative HTTP URL - this works in both Tauri and development
const absolutePath = filePath.startsWith('/') ? filePath : `/${filePath}` if (filename === 'video.mp4') {
const fileUrl = `file://${absolutePath}` videoSrc.value = '/video.mp4'
videoSrc.value = fileUrl } else {
console.log('🎥 Using file:// URL:') videoSrc.value = `/${filename}`
}
console.log('🎥 Using HTTP URL for video:')
console.log(' - Original path:', raw) console.log(' - Original path:', raw)
console.log(' - File path:', filePath) console.log(' - HTTP URL:', videoSrc.value)
console.log(' - File URL:', fileUrl)
} }
// Watch for changes in currentVideo and update videoSrc // Watch for changes in currentVideo and update videoSrc
@@ -288,6 +291,8 @@ function onVideoError(event) {
// Initialize fullscreen if configured // Initialize fullscreen if configured
onMounted(async () => { onMounted(async () => {
console.log('🔧 Component mounted, initializing...') console.log('🔧 Component mounted, initializing...')
console.log('📁 Current directory:', window.location.href)
if (appConfig.player.autoFullscreen) { if (appConfig.player.autoFullscreen) {
console.log('🔧 Auto fullscreen enabled') console.log('🔧 Auto fullscreen enabled')
// Request fullscreen // Request fullscreen
@@ -306,6 +311,18 @@ onMounted(async () => {
await updatePlayerState() await updatePlayerState()
console.log('✅ Component initialization complete') console.log('✅ Component initialization complete')
// Additional debug: check if video.mp4 exists in public folder
try {
const response = await fetch('/video.mp4', { method: 'HEAD' })
if (response.ok) {
console.log('📹 Found video.mp4 in public folder via HTTP')
} else {
console.log('❌ video.mp4 not accessible via HTTP')
}
} catch (e) {
console.log('🌐 Cannot check video.mp4 via HTTP (expected in Tauri)')
}
}) })
// Setup Tauri event listeners // Setup Tauri event listeners
@@ -373,8 +390,17 @@ async function handlePlayerCommand(command) {
case 'play': case 'play':
if (videoElement.value) { if (videoElement.value) {
try { try {
await videoElement.value.play() // Ensure video is ready before attempting to play
isPlaying.value = true if (videoElement.value.readyState >= 2) {
await videoElement.value.play()
isPlaying.value = true
} else {
// Wait for video to be ready
videoElement.value.addEventListener('canplay', () => {
videoElement.value.play().catch(console.error)
isPlaying.value = true
}, { once: true })
}
} catch (error) { } catch (error) {
console.error('Play error:', error) console.error('Play error:', error)
} }

View File

@@ -38,11 +38,15 @@ pub fn run() {
let player_state_for_load = player_state.clone(); let player_state_for_load = player_state.clone();
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
let mut candidates: Vec<std::path::PathBuf> = Vec::new(); let mut candidates: Vec<std::path::PathBuf> = Vec::new();
// Add current working directory
if let Ok(cwd) = std::env::current_dir() { if let Ok(cwd) = std::env::current_dir() {
log::info!("🔍 Searching in current working directory: {}", cwd.display()); log::info!("🔍 Searching in current working directory: {}", cwd.display());
candidates.push(cwd.join("video.mp4")); candidates.push(cwd.join("video.mp4"));
candidates.push(cwd.join("public").join("video.mp4")); candidates.push(cwd.join("public").join("video.mp4"));
} }
// Add executable directory and its ancestors
if let Ok(exe_path) = std::env::current_exe() { if let Ok(exe_path) = std::env::current_exe() {
log::info!("📁 Executable path: {}", exe_path.display()); log::info!("📁 Executable path: {}", exe_path.display());
let mut ancestor_opt = exe_path.parent(); let mut ancestor_opt = exe_path.parent();
@@ -63,57 +67,66 @@ pub fn run() {
} }
for candidate in candidates { for candidate in candidates {
if tokio::fs::metadata(&candidate).await.is_ok() { match tokio::fs::metadata(&candidate).await {
let path_string = candidate.to_string_lossy().to_string(); Ok(metadata) => {
log::info!("✅ Found video file: {}", path_string); if metadata.is_file() {
// Update backend player state let path_string = candidate.to_string_lossy().to_string();
{ log::info!("✅ Found video file: {}", path_string);
let mut state = player_state_for_load.lock().await;
let title = candidate.file_name().and_then(|n| n.to_str()).unwrap_or("video.mp4").to_string(); // Update backend player state
let video_info = VideoInfo { {
path: path_string.clone(), let mut state = player_state_for_load.lock().await;
title, let title = candidate.file_name().and_then(|n| n.to_str()).unwrap_or("video.mp4").to_string();
duration: None, let video_info = VideoInfo {
size: None, path: path_string.clone(),
format: None, title,
}; duration: None,
state.load_video(video_info); size: None,
// 默认启用循环并开始播放 format: None,
state.set_loop(true); };
state.play(); state.load_video(video_info);
state.set_loop(true);
state.play();
}
// Send commands to frontend with increasing delays for reliability
let app_handle_clone = app_handle_load.clone();
let path_for_load = path_string.clone();
// Immediate load
tauri::async_runtime::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
let _ = app_handle_clone.emit("player-command", serde_json::json!({
"type": "loadVideo",
"path": "video.mp4"
}));
});
// Set loop after load
let app_handle_clone2 = app_handle_load.clone();
tauri::async_runtime::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let _ = app_handle_clone2.emit("player-command", serde_json::json!({
"type": "setLoop",
"enabled": true
}));
});
// Play after load and loop are set
let app_handle_clone3 = app_handle_load.clone();
tauri::async_runtime::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
let _ = app_handle_clone3.emit("player-command", serde_json::json!({
"type": "play"
}));
});
return; // Exit early since we found a video
}
}
Err(e) => {
log::debug!("❌ File not found or inaccessible: {} - {}", candidate.display(), e);
} }
// Notify frontend to load and play the video (use absolute path; frontend will add file:// if needed)
let _ = app_handle_load.emit("player-command", serde_json::json!({
"type": "loadVideo",
"path": path_string
}));
let _ = app_handle_load.emit("player-command", serde_json::json!({
"type": "setLoop",
"enabled": true
}));
let _ = app_handle_load.emit("player-command", serde_json::json!({
"type": "play"
}));
// Re-emit after a short delay to ensure frontend listeners are ready in dev mode
let app_handle_clone = app_handle_load.clone();
let delayed_path = path_string.clone();
tauri::async_runtime::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(800)).await;
let _ = app_handle_clone.emit("player-command", serde_json::json!({
"type": "loadVideo",
"path": delayed_path
}));
let _ = app_handle_clone.emit("player-command", serde_json::json!({
"type": "setLoop",
"enabled": true
}));
let _ = app_handle_clone.emit("player-command", serde_json::json!({
"type": "play"
}));
});
return; // Exit early since we found a video
} }
} }