@@ -271,16 +271,38 @@ async fn process_job(job: Job) -> Result<()> {
271271 }
272272 }
273273
274- let output_path = format ! ( "{}/output.mp4" , temp_dir) ;
275- info ! ( "Output path: {}" , output_path) ;
276-
277274 // Build FFmpeg filter complex based on quadrant selection
278275 let filter_complex = build_filter_complex ( & job. selection ) ?;
279276 info ! ( "FFmpeg filter: {}" , filter_complex) ;
280277
281- info ! ( "Starting FFmpeg..." ) ;
278+ // Create the output folder on WebDAV if needed (before FFmpeg runs)
279+ // job.output_path is like "processed/filename.mp4"
280+ if let Some ( folder_end) = job. output_path . rfind ( '/' ) {
281+ let folder = & job. output_path [ ..folder_end] ;
282+ if !folder. is_empty ( ) {
283+ info ! ( "Creating WebDAV client to ensure folder exists..." ) ;
284+ let dav_client = WebDavClient :: new ( & job. webdav_config ) ?;
285+ info ! ( "Ensuring folder exists: {}" , folder) ;
286+ if let Err ( e) = dav_client. ensure_folder_exists ( folder) . await {
287+ warn ! ( "Could not create folder {}: {} (may already exist)" , folder, e) ;
288+ }
289+ }
290+ }
291+
292+ // Build WebDAV URL for direct output from FFmpeg
293+ let output_url = build_webdav_upload_url ( & job. webdav_config , & job. output_path ) ;
294+ info ! ( "FFmpeg will output directly to WebDAV: {}" , job. output_path) ;
295+ // Log URL without credentials for debugging
296+ let output_url_safe = output_url. replacen (
297+ & format ! ( "://{}:{}@" , encode( & job. webdav_config. username) , encode( & job. webdav_config. password) ) ,
298+ "://[credentials]@" ,
299+ 1
300+ ) ;
301+ info ! ( "Output URL (redacted): {}" , output_url_safe) ;
302+
303+ info ! ( "Starting FFmpeg with direct WebDAV output..." ) ;
282304
283- // Run FFmpeg command
305+ // Run FFmpeg command - output directly to WebDAV
284306 let ffmpeg_result = tokio:: process:: Command :: new ( "ffmpeg" )
285307 . arg ( "-y" ) // Overwrite output
286308 . arg ( "-i" ) . arg ( & video_url) // Input video
@@ -293,7 +315,8 @@ async fn process_job(job: Job) -> Result<()> {
293315 . arg ( "-preset" ) . arg ( "veryfast" )
294316 . arg ( "-threads" ) . arg ( "0" )
295317 . arg ( "-c:a" ) . arg ( "copy" )
296- . arg ( & output_path)
318+ . arg ( "-method" ) . arg ( "PUT" ) // Use HTTP PUT for WebDAV
319+ . arg ( & output_url)
297320 . output ( )
298321 . await ;
299322
@@ -310,36 +333,7 @@ async fn process_job(job: Job) -> Result<()> {
310333 }
311334
312335 if output. status . success ( ) {
313- info ! ( "FFmpeg processing successful!" ) ;
314-
315- // Check output file
316- match fs:: metadata ( & output_path) {
317- Ok ( meta) => info ! ( "Output file size: {} bytes" , meta. len( ) ) ,
318- Err ( e) => error ! ( "Failed to stat output file: {}" , e) ,
319- }
320-
321- // Upload result back to WebDAV
322- info ! ( "Reading output file..." ) ;
323- let output_data = fs:: read ( & output_path) ?;
324- info ! ( "Output file read, size: {} bytes" , output_data. len( ) ) ;
325-
326- info ! ( "Creating WebDAV client..." ) ;
327- let dav_client = WebDavClient :: new ( & job. webdav_config ) ?;
328-
329- // Extract just the filename from the full path for upload
330- // output_path is like /remote.php/dav/files/jasper/VideoTest/test-2s_processed.mp4
331- // We need just the filename: test-2s_processed.mp4
332- let upload_filename = job. output_path
333- . rsplit ( '/' )
334- . next ( )
335- . unwrap_or ( & job. output_path ) ;
336-
337- info ! ( "Uploading processed video as: {} (from path: {})" , upload_filename, job. output_path) ;
338- match dav_client. upload_file ( upload_filename, output_data) . await {
339- Ok ( _) => info ! ( "Upload successful!" ) ,
340- Err ( e) => error ! ( "Upload FAILED: {}" , e) ,
341- }
342-
336+ info ! ( "FFmpeg processing and direct WebDAV upload successful!" ) ;
343337 info ! ( "Job {} completed successfully" , job. id) ;
344338
345339 // Update job to completed via queue URL
@@ -352,6 +346,7 @@ async fn process_job(job: Job) -> Result<()> {
352346 }
353347 } else {
354348 error ! ( "FFmpeg FAILED with exit code: {}" , output. status) ;
349+ error ! ( "Direct WebDAV output failed - check FFmpeg stderr above for details" ) ;
355350
356351 if let Some ( queue_url) = & job. webdav_config . queue_url {
357352 let _ = update_job_status_remote ( queue_url, & job. id , JobStatus :: Failed , None ) . await ;
@@ -427,6 +422,18 @@ fn build_webdav_download_url(config: &WebDavConfig, path: &str) -> String {
427422 . replacen ( "://" , & format ! ( "://{}:{}@" , encode( & config. username) , encode( & config. password) ) , 1 )
428423}
429424
425+ fn build_webdav_upload_url ( config : & WebDavConfig , output_path : & str ) -> String {
426+ // Build full WebDAV URL for uploading
427+ // config.url is like: https://cloud.example.com/remote.php/dav/files/user/VideoTest
428+ // output_path is like: processed/filename.mp4
429+ // Result: https://user:pass@cloud.example.com/remote.php/dav/files/user/VideoTest/processed/filename.mp4
430+
431+ let base_url = config. url . trim_end_matches ( '/' ) ;
432+ let full_url = format ! ( "{}/{}" , base_url, output_path) ;
433+
434+ full_url. replacen ( "://" , & format ! ( "://{}:{}@" , encode( & config. username) , encode( & config. password) ) , 1 )
435+ }
436+
430437async fn update_job_status_remote (
431438 queue_url : & str ,
432439 job_id : & str ,
0 commit comments