暂时无法自动播放

This commit is contained in:
2025-08-17 22:07:37 +08:00
parent 196ee46a8d
commit 90e4a01e62
13 changed files with 410 additions and 21 deletions

View File

@@ -39,6 +39,10 @@
"os:allow-locale",
"fs:allow-document-read",
"fs:allow-document-write",
"fs:default",
"fs:allow-read-dir",
"fs:allow-read-file",
"fs:allow-stat",
"store:default",
"core:webview:allow-create-webview",
"core:webview:allow-create-webview-window"

View File

@@ -1 +1 @@
{"main":{"identifier":"main","description":"Capabilities for the app window","local":true,"windows":["main","secondary"],"permissions":["core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":["-c",{"validator":"\\S+"}],"cmd":"sh","name":"exec-sh","sidecar":false}]},"notification:default","os:allow-platform","os:allow-arch","os:allow-family","os:allow-version","os:allow-locale","fs:allow-document-read","fs:allow-document-write","store:default","core:webview:allow-create-webview","core:webview:allow-create-webview-window"]}}
{"main":{"identifier":"main","description":"Capabilities for the app window","local":true,"windows":["main","secondary"],"permissions":["core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":["-c",{"validator":"\\S+"}],"cmd":"sh","name":"exec-sh","sidecar":false}]},"notification:default","os:allow-platform","os:allow-arch","os:allow-family","os:allow-version","os:allow-locale","fs:allow-document-read","fs:allow-document-write","fs:default","fs:allow-read-dir","fs:allow-read-file","fs:allow-stat","store:default","core:webview:allow-create-webview","core:webview:allow-create-webview-window"]}}

View File

@@ -7,11 +7,12 @@ mod commands;
use tauri::{
menu::{Menu, MenuItem},
tray::TrayIconBuilder,
Manager
Manager,
Emitter
};
use tokio::sync::Mutex;
use std::sync::Arc;
use player_state::PlayerState;
use player_state::{PlayerState, VideoInfo};
use websocket_server::WebSocketServer;
pub fn run() {
@@ -22,7 +23,7 @@ pub fn run() {
app.manage(player_state.clone());
// Start WebSocket server in background using tauri's async runtime
let ws_server = WebSocketServer::new(8080, player_state.clone());
let ws_server = WebSocketServer::new(6666, player_state.clone());
let app_handle = app.handle().clone();
// Use tauri's runtime handle to spawn the async task
@@ -32,6 +33,93 @@ pub fn run() {
}
});
// Try to auto-load video.mp4 from common locations (cwd, public/, executable dir)
let app_handle_load = app.handle().clone();
let player_state_for_load = player_state.clone();
tauri::async_runtime::spawn(async move {
let mut candidates: Vec<std::path::PathBuf> = Vec::new();
if let Ok(cwd) = std::env::current_dir() {
log::info!("🔍 Searching in current working directory: {}", cwd.display());
candidates.push(cwd.join("video.mp4"));
candidates.push(cwd.join("public").join("video.mp4"));
}
if let Ok(exe_path) = std::env::current_exe() {
log::info!("📁 Executable path: {}", exe_path.display());
let mut ancestor_opt = exe_path.parent();
let mut steps = 0;
while let Some(dir) = ancestor_opt {
log::info!("🔍 Searching in ancestor directory: {}", dir.display());
candidates.push(dir.join("video.mp4"));
candidates.push(dir.join("public").join("video.mp4"));
steps += 1;
if steps > 6 { break; }
ancestor_opt = dir.parent();
}
}
log::info!("📋 Total search candidates: {}", candidates.len());
for (i, candidate) in candidates.iter().enumerate() {
log::info!(" {}. {}", i + 1, candidate.display());
}
for candidate in candidates {
if tokio::fs::metadata(&candidate).await.is_ok() {
let path_string = candidate.to_string_lossy().to_string();
log::info!("✅ Found video file: {}", path_string);
// Update backend player state
{
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();
let video_info = VideoInfo {
path: path_string.clone(),
title,
duration: None,
size: None,
format: None,
};
state.load_video(video_info);
// 默认启用循环并开始播放
state.set_loop(true);
state.play();
}
// 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
}
}
log::warn!("❌ No video.mp4 file found in any search location");
});
// Setup tray
let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&quit_i])?;
@@ -50,7 +138,7 @@ pub fn run() {
})
.build(app)?;
log::info!("Video Player initialized, WebSocket server starting on port 8080");
log::info!("Video Player initialized, WebSocket server starting on port 6666");
Ok(())
})
.invoke_handler(tauri::generate_handler![

View File

@@ -1,6 +1,11 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use env_logger::Env;
fn main() {
env_logger::init();
let env = Env::default().default_filter_or("info");
let _ = env_logger::Builder::from_env(env)
.format_timestamp_millis()
.try_init();
video_player_lib::run();
}

View File

@@ -17,7 +17,7 @@ impl WebSocketServer {
}
pub async fn start(&self, app_handle: AppHandle) -> Result<(), Box<dyn std::error::Error>> {
let addr = format!("127.0.0.1:{}", self.port);
let addr = format!("0.0.0.0:{}", self.port);
let listener = TcpListener::bind(&addr).await?;
log::info!("WebSocket server listening on: {}", addr);
@@ -67,6 +67,23 @@ async fn handle_connection(
let status_update = StatusUpdate::new(state.clone());
let message = serde_json::to_string(&status_update)?;
ws_sender.send(Message::Text(message)).await?;
if let Some(video) = &state.current_video {
let load_msg = serde_json::json!({
"type": "command",
"data": { "type": "loadVideo", "path": video.path }
});
ws_sender.send(Message::Text(load_msg.to_string())).await.ok();
let loop_msg = serde_json::json!({
"type": "command",
"data": { "type": "setLoop", "enabled": state.is_looping }
});
ws_sender.send(Message::Text(loop_msg.to_string())).await.ok();
let play_msg = serde_json::json!({
"type": "command",
"data": { "type": "play" }
});
ws_sender.send(Message::Text(play_msg.to_string())).await.ok();
}
}
// Emit connection status to frontend
@@ -85,6 +102,12 @@ async fn handle_connection(
if ws_message.msg_type == "command" {
if let Ok(command) = serde_json::from_value::<PlaybackCommand>(ws_message.data) {
handle_playback_command(command, &player_state, &app_handle).await?;
// Send updated status to client after handling command
let state = player_state.lock().await;
let status_update = StatusUpdate::new(state.clone());
let message = serde_json::to_string(&status_update)?;
ws_sender.send(Message::Text(message)).await?;
}
}
}