diff --git a/Cargo.lock b/Cargo.lock index dfa7a88..975dc21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,9 +397,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys 0.52.0", @@ -430,6 +430,7 @@ dependencies = [ "serde_json", "state", "strip-ansi-escapes", + "tempfile", "textwrap", "thiserror", "tokio", @@ -462,6 +463,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "fs-err" version = "2.11.0" @@ -504,7 +511,19 @@ checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -612,9 +631,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "linked-hash-map" @@ -628,6 +647,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "lock_api" version = "0.4.11" @@ -738,7 +763,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -896,6 +921,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -923,7 +954,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.12", ] [[package]] @@ -1014,7 +1045,20 @@ dependencies = [ "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.11.0", "windows-sys 0.52.0", ] @@ -1244,13 +1288,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.52.0", +] + [[package]] name = "terminal_size" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix", + "rustix 0.38.31", "windows-sys 0.48.0", ] @@ -1468,6 +1525,24 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -1703,6 +1778,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + [[package]] name = "zerocopy" version = "0.7.32" diff --git a/Cargo.toml b/Cargo.toml index 5d22d1a..ea002d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,3 +83,4 @@ linked-hash-map = { workspace = true } parking_lot = { workspace = true } textwrap = { workspace = true } chrono = { workspace = true } +tempfile = "3.23.0" diff --git a/src/commands/transcode/jobs/transcode.rs b/src/commands/transcode/jobs/transcode.rs index 374a9f6..e19f3e1 100644 --- a/src/commands/transcode/jobs/transcode.rs +++ b/src/commands/transcode/jobs/transcode.rs @@ -1,8 +1,10 @@ +use std::io::Seek; use std::path::PathBuf; -use std::process::{Command, Stdio}; +use std::process::Command; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; use std::{fs, thread}; +use tempfile::tempfile; use crossbeam::channel::Sender; use euphony_configuration::get_path_extension_or_empty; @@ -167,10 +169,28 @@ impl FileJob for TranscodeAudioFileJob { /* * Step 2: run ffmpeg (transcodes audio) */ + let mut stdout_file = tempfile() + .into_diagnostic() + .wrap_err_with(|| { + miette!("Could not create a temporary file for ffmpeg's stdout.") + })?; + let mut stderr_file = tempfile() + .into_diagnostic() + .wrap_err_with(|| { + miette!("Could not create a temporary file for ffmpeg's stderr.") + })?; let mut ffmpeg_child_process = Command::new(&self.ffmpeg_binary_path) .args(&self.ffmpeg_arguments) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) + .stdout(stdout_file.try_clone() + .into_diagnostic() + .wrap_err_with(|| { + miette!("Could not duplicate the stdout temporary file descriptor.") + })?) + .stderr(stderr_file.try_clone() + .into_diagnostic() + .wrap_err_with(|| { + miette!("Could not duplicate the stderr temporary file descriptor.") + })?) .spawn() .into_diagnostic() .wrap_err_with(|| { @@ -247,15 +267,12 @@ impl FileJob for TranscodeAudioFileJob { Ok(()) } else { // Everything was normal. - let ffmpeg_output = ffmpeg_child_process - .wait_with_output() + let ffmpeg_exit_code = ffmpeg_child_process + .wait() .into_diagnostic() - .wrap_err_with(|| miette!("Could not get ffmpeg output."))?; - - let ffmpeg_exit_code = ffmpeg_output - .status + .wrap_err_with(|| miette!("Could not wait for the ffmpeg subprocess."))? .code() - .ok_or_else(|| miette!("No ffmpeg exit code?!"))?; + .ok_or_else(|| miette!("No ffmpeg exit code! Was it killed by a signal?"))?; // Extract ffmpeg stdout/stderr/exit code if necessary. let processing_result = if ffmpeg_exit_code == 0 { @@ -269,16 +286,19 @@ impl FileJob for TranscodeAudioFileJob { FileJobResult::Okay { verbose_info } } else { - let ffmpeg_stdout = String::from_utf8(ffmpeg_output.stdout) + // Duplicated file handles share seek position, so we need to rewind before reading. + stdout_file.seek(std::io::SeekFrom::Start(0)).unwrap(); + let ffmpeg_stdout = std::io::read_to_string(stdout_file) .into_diagnostic() .wrap_err_with(|| { - miette!("Could not parse ffmpeg stdout.") + miette!("Could not read temporary file with ffmpeg stdout.") })?; - let ffmpeg_stderr = String::from_utf8(ffmpeg_output.stderr) + stderr_file.seek(std::io::SeekFrom::Start(0)).unwrap(); + let ffmpeg_stderr = std::io::read_to_string(stderr_file) .into_diagnostic() .wrap_err_with(|| { - miette!("could not parse ffmpeg stderr.") + miette!("Could not read temporary file with ffmpeg stderr.") })?; let error = format!(