Skip to content

Commit fd5574a

Browse files
Output directly to WebDAV from FFmpeg instead of local file
- FFmpeg now writes directly to WebDAV URL using HTTP PUT - Eliminates need to store output locally and upload separately - Better for large files - no disk space needed, single operation - Still creates the processed/ folder before FFmpeg runs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 985958d commit fd5574a

File tree

1 file changed

+43
-43
lines changed

1 file changed

+43
-43
lines changed

src/jobs.rs

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
282302

283-
// Run FFmpeg command
303+
info!("Starting FFmpeg with direct WebDAV output...");
304+
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,43 +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-
// job.output_path is like "processed/filename.mp4"
330-
// We need to create the "processed" folder if it doesn't exist
331-
let upload_path = &job.output_path;
332-
333-
// Check if output_path contains a folder (has a /)
334-
if let Some(folder_end) = upload_path.rfind('/') {
335-
let folder = &upload_path[..folder_end];
336-
if !folder.is_empty() {
337-
info!("Ensuring folder exists: {}", folder);
338-
if let Err(e) = dav_client.ensure_folder_exists(folder).await {
339-
warn!("Could not create folder {}: {} (may already exist)", folder, e);
340-
}
341-
}
342-
}
343-
344-
info!("Uploading processed video to: {}", upload_path);
345-
match dav_client.upload_file(upload_path, output_data).await {
346-
Ok(_) => info!("Upload successful!"),
347-
Err(e) => error!("Upload FAILED: {}", e),
348-
}
349-
336+
info!("FFmpeg processing and direct WebDAV upload successful!");
350337
info!("Job {} completed successfully", job.id);
351338

352339
// Update job to completed via queue URL
@@ -359,6 +346,7 @@ async fn process_job(job: Job) -> Result<()> {
359346
}
360347
} else {
361348
error!("FFmpeg FAILED with exit code: {}", output.status);
349+
error!("Direct WebDAV output failed - check FFmpeg stderr above for details");
362350

363351
if let Some(queue_url) = &job.webdav_config.queue_url {
364352
let _ = update_job_status_remote(queue_url, &job.id, JobStatus::Failed, None).await;
@@ -434,6 +422,18 @@ fn build_webdav_download_url(config: &WebDavConfig, path: &str) -> String {
434422
.replacen("://", &format!("://{}:{}@", encode(&config.username), encode(&config.password)), 1)
435423
}
436424

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+
437437
async fn update_job_status_remote(
438438
queue_url: &str,
439439
job_id: &str,

0 commit comments

Comments
 (0)