diff --git a/backend/src/config.rs b/backend/src/config.rs index fe8a477..0efde5c 100644 --- a/backend/src/config.rs +++ b/backend/src/config.rs @@ -12,6 +12,7 @@ pub struct AppConfig { pub render_options: RenderSettings, pub app_update: AppUpdate, pub font_path: String, + pub out_path: String, } const CONFIG_NAME: &str = "saved_settings"; diff --git a/ui/src/app.rs b/ui/src/app.rs index f0a92b8..e85320a 100644 --- a/ui/src/app.rs +++ b/ui/src/app.rs @@ -31,6 +31,7 @@ pub struct WalksnailOsdTool { pub video_info: Option, pub osd_file: Option, pub font_file: Option, + pub out_path: Option, pub srt_file: Option, pub ui_dimensions: UiDimensions, pub to_ffmpeg_sender: Option>, @@ -78,6 +79,9 @@ impl WalksnailOsdTool { let font_path = PathBuf::from(saved_settings.font_path); let font_file = font::FontFile::open(font_path).ok(); + // Load last used output path + let out_path = Some(PathBuf::from(saved_settings.out_path)); + let app_update = AppUpdate { promise: update_check_promise, ..Default::default() @@ -94,6 +98,7 @@ impl WalksnailOsdTool { osd_options, srt_options, font_file, + out_path, app_update, app_version, target, diff --git a/ui/src/bottom_panel.rs b/ui/src/bottom_panel.rs index 611688c..44400b0 100644 --- a/ui/src/bottom_panel.rs +++ b/ui/src/bottom_panel.rs @@ -11,12 +11,24 @@ impl WalksnailOsdTool { ui.add_space(5.0); ui.horizontal(|ui| { self.start_stop_render_button(ui); + self.out_path_label(ui); self.render_progress(ui); }); ui.add_space(2.0); }); } + fn out_path_label(&mut self, ui: &mut Ui) { + if self.render_status.is_not_in_progress() { + if let Some(out_path) = &self.out_path { + let path = out_path.as_path().to_string_lossy(); + ui.label(path); + } else { + ui.label("-"); + } + } + } + fn start_stop_render_button(&mut self, ui: &mut Ui) { let button_size = vec2(110.0, 40.0); if self.render_status.is_not_in_progress() { @@ -30,7 +42,8 @@ impl WalksnailOsdTool { { tracing::info!("Start render button clicked"); self.render_status.start_render(); - if let (Some(video_path), Some(osd_file), Some(font_file), Some(video_info), Some(srt_file)) = ( + if let (Some(out_path), Some(video_path), Some(osd_file), Some(font_file), Some(video_info), Some(srt_file)) = ( + &self.out_path, &self.video_file, &self.osd_file, &self.font_file, @@ -47,7 +60,7 @@ impl WalksnailOsdTool { match start_video_render( &self.dependencies.ffmpeg_path, video_path, - &get_output_video_path(video_path), + &get_output_video_path(out_path, video_path), osd_file.frames.clone(), srt_file.frames.clone(), font_file.clone(), @@ -111,7 +124,13 @@ impl WalksnailOsdTool { } Status::Completed => { ui.vertical(|ui| { - ui.add(ProgressBar::new(1.0).text("Done")); + if let (Some(out_path), Some(input_video_path)) = (&self.out_path, &self.video_file) + { + let out = &get_output_video_path(out_path, input_video_path); + let path = out.as_path().to_string_lossy(); + let name: String = out.file_name().unwrap().to_string_lossy().into(); + ui.hyperlink_to( name, path); + } }); } Status::Cancelled { progress_pct } => { diff --git a/ui/src/top_panel.rs b/ui/src/top_panel.rs index dda0412..bf6979d 100644 --- a/ui/src/top_panel.rs +++ b/ui/src/top_panel.rs @@ -8,6 +8,7 @@ impl WalksnailOsdTool { ui.add_space(5.0); ui.horizontal(|ui| { self.import_files(ui, ctx); + self.output_path_button(ui); self.reset_files(ui); ui.add_space(ui.available_width() - 55.0); self.toggle_light_dark_theme(ui, ctx); @@ -58,6 +59,19 @@ impl WalksnailOsdTool { }); } + fn output_path_button(&mut self, ui: &mut Ui) { + if ui + .add_enabled(self.render_status.is_not_in_progress(), Button::new("Output path")) + .clicked() + { + tracing::info!("Output file button clicked"); + if let Some(file_handles) = rfd::FileDialog::new().add_filter("MP4 files", &["mp4"]).pick_folder() { + tracing::info!("Output {:?}", file_handles); + self.out_path = Some(file_handles); + } + } + } + fn reset_files(&mut self, ui: &mut Ui) { if ui .add_enabled(self.render_status.is_not_in_progress(), Button::new("Reset files")) diff --git a/ui/src/util.rs b/ui/src/util.rs index f52c4c9..d34f80a 100644 --- a/ui/src/util.rs +++ b/ui/src/util.rs @@ -44,6 +44,11 @@ impl WalksnailOsdTool { // Try to load the matching OSD and SRT files self.import_osd_file(&[matching_file_with_extension(video_file, "osd")]); self.import_srt_file(&[matching_file_with_extension(video_file, "srt")]); + + // If the output path is not set, set it to the same directory as the video file + if self.out_path.is_none() { + self.out_path = Some(video_file.parent().unwrap().to_path_buf()); + } } } @@ -102,10 +107,10 @@ pub fn format_minutes_seconds(duration: &Duration) -> String { format!("{}:{:0>2}", minutes, seconds) } -pub fn get_output_video_path(input_video_path: &Path) -> PathBuf { +pub fn get_output_video_path(out_video_path: &Path, input_video_path: &Path) -> PathBuf { let input_video_file_name = input_video_path.file_stem().unwrap().to_string_lossy(); let output_video_file_name = format!("{}_with_osd.mp4", input_video_file_name); - let mut output_video_path = input_video_path.parent().unwrap().to_path_buf(); + let mut output_video_path = out_video_path.to_path_buf(); output_video_path.push(output_video_file_name); output_video_path } @@ -172,6 +177,12 @@ impl Into for &mut WalksnailOsdTool { .unwrap_or_default() .to_string_lossy() .to_string(), + out_path: self + .out_path + .as_ref() + .unwrap() + .to_string_lossy() + .to_string(), } } }