@@ -109,6 +109,7 @@ struct GpuSetup {
109109
110110fn main ( ) {
111111 tauri:: Builder :: default ( )
112+ . plugin ( tauri_plugin_dialog:: init ( ) )
112113 . plugin ( tauri_plugin_store:: Builder :: default ( ) . build ( ) )
113114 . setup ( |app| {
114115 let data_dir = match local_data_dir ( ) {
@@ -152,6 +153,7 @@ fn main() {
152153 ensure_torch_device,
153154 start_backend,
154155 open_url,
156+ save_audio_file,
155157 store_get,
156158 store_set,
157159 mark_store_migration_done,
@@ -961,6 +963,35 @@ fn open_url(url: String) -> Result<(), String> {
961963 Ok ( ( ) )
962964}
963965
966+ #[ tauri:: command]
967+ async fn save_audio_file ( app : tauri:: AppHandle , url : String , filename : String ) -> Result < ( ) , String > {
968+ if !url. starts_with ( "http://" ) && !url. starts_with ( "https://" ) {
969+ return Err ( "only http/https URLs are permitted" . to_string ( ) ) ;
970+ }
971+ use tauri_plugin_dialog:: DialogExt ;
972+ let dest = app
973+ . dialog ( )
974+ . file ( )
975+ . set_file_name ( & filename)
976+ . blocking_save_file ( ) ;
977+ let Some ( file_path) = dest else {
978+ return Ok ( ( ) ) ; // user cancelled
979+ } ;
980+ let dest = file_path. into_path ( ) . map_err ( |e| e. to_string ( ) ) ?;
981+ let client = reqwest:: Client :: new ( ) ;
982+ let resp = client
983+ . get ( & url)
984+ . send ( )
985+ . await
986+ . map_err ( |e| format ! ( "fetch failed: {e}" ) ) ?;
987+ if !resp. status ( ) . is_success ( ) {
988+ return Err ( format ! ( "backend returned HTTP {}" , resp. status( ) ) ) ;
989+ }
990+ let bytes = resp. bytes ( ) . await . map_err ( |e| format ! ( "read failed: {e}" ) ) ?;
991+ std:: fs:: write ( & dest, & bytes) . map_err ( |e| format ! ( "write failed: {e}" ) ) ?;
992+ Ok ( ( ) )
993+ }
994+
964995fn stop_backend ( state : & BackendState ) {
965996 if let Ok ( mut guard) = state. child . lock ( ) {
966997 if let Some ( child) = guard. as_mut ( ) {
0 commit comments