From a776191f71676192c4df42d1dfd02eb420ae46a6 Mon Sep 17 00:00:00 2001 From: Aaron Lichtman Date: Tue, 6 Feb 2024 04:05:42 -0800 Subject: [PATCH 1/5] Don't create the output folder until the user confirms Fix #14 --- src/main.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7a585cf..3ee9043 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,15 +27,18 @@ fn main() { print_header(); let args = CliArgs::parse(); - // Canonicalize input and output paths up front, creating the output directory if needed. + // Canonicalize input path up front. We don't handle the output path until later to avoid creating the output path if the user cancels the operation. let input_dir = args .input .clone() .unwrap() .canonicalize() .expect("Could not canonicalize input dir path. Does it exist?"); - let output_dir = normalize_and_create_if_needed(args.output.clone().unwrap()); + actually_do_things_with_input_and_output_paths(input_dir, args); +} + +fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliArgs) { let input_files = filesystem::get_files_in_directory(input_dir.to_str().unwrap()); if input_files.is_empty() { error!( @@ -54,6 +57,10 @@ fn main() { // Extract data for each video file let videos = parse_gopro_files_directory(input_files); + + // TODO: Ensure all videos are valid mp4s. (#10) + println!("{:?}", videos); + // Sort the videos by video number, preparing them to be "concat demuxed" by ffmpeg https://stackoverflow.com/a/11175851 let mut multichapter_videos_sorted = gopro::sort_gopro_files(videos); // Filter out videos that only have one chapter to be renamed separately @@ -75,6 +82,7 @@ fn main() { process::exit(0); } } + let output_dir = normalize_and_create_if_needed(args.output.clone().unwrap()); combine_multichapter_videos( multichapter_videos_sorted.clone(), From 3f82b80c34488f60cd465997a43424eb4e747885 Mon Sep 17 00:00:00 2001 From: Aaron Lichtman Date: Tue, 6 Feb 2024 04:09:51 -0800 Subject: [PATCH 2/5] Wording changes --- src/main.rs | 2 +- src/printing.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3ee9043..1fc6eaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,7 @@ fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliA let videos = parse_gopro_files_directory(input_files); // TODO: Ensure all videos are valid mp4s. (#10) - println!("{:?}", videos); + // println!("{:?}", videos); // Sort the videos by video number, preparing them to be "concat demuxed" by ffmpeg https://stackoverflow.com/a/11175851 let mut multichapter_videos_sorted = gopro::sort_gopro_files(videos); diff --git a/src/printing.rs b/src/printing.rs index f94fa43..5412026 100644 --- a/src/printing.rs +++ b/src/printing.rs @@ -53,7 +53,7 @@ pub fn print_expected_output( total_chapters_to_combine += value.len(); } info!( - "Found {} video(s) with {} total chapters to combine", + "These make up {} video(s), with {} total chapters to combine", total_videos_to_output.to_string().blue().bold(), total_chapters_to_combine.to_string().blue().bold() ); From 29b85682e2e5ccf02fed68f7187316ecd982d7af Mon Sep 17 00:00:00 2001 From: Aaron Lichtman Date: Tue, 6 Feb 2024 04:45:48 -0800 Subject: [PATCH 3/5] track *.MP4 files using Git LFS --- .gitattributes | 2 ++ .gitignore | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c76b5ad --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.MP4 filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index c81097a..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ /target -output -tests/working_test_data -tests/real_videos From 76205d2b9f7c6a0f95ae0ac60db9fbd8012f0d78 Mon Sep 17 00:00:00 2001 From: Aaron Lichtman Date: Tue, 6 Feb 2024 04:47:19 -0800 Subject: [PATCH 4/5] Integration Testing! ``` $ cargo test ``` now runs an integration test that uses the `gopro-chaptered-video-assembler` binary to create real video output. A merkle tree is then constructed, and the root node hash is compared with the expected output. I've verified that the test fails when unexpected files are in either of the directories, or the files don't match. The reliance on extensive manual testing was making it harder to want to work on this. Fix #12 --- .vscode/launch.json | 146 ++--- Cargo.lock | 690 +++++++++++++++------- Cargo.toml | 8 +- src/cli.rs | 6 +- src/main.rs | 38 +- src/printing.rs | 13 +- tests/data/expected_output/GoPro_2352.mp4 | 3 + tests/data/expected_output/GoPro_4855.mp4 | 3 + tests/data/expected_output/GoPro_7322.mp4 | 3 + tests/data/expected_output/GoPro_7329.mp4 | 3 + tests/data/real_videos/GH017322.MP4 | 3 + tests/data/real_videos/GH017329.MP4 | 3 + tests/data/real_videos/GH027322.MP4 | 3 + tests/data/real_videos/GH027329.MP4 | 3 + tests/data/real_videos/GX012352.MP4 | 3 + tests/data/real_videos/GX014855.MP4 | 3 + tests/integration_test.rs | 70 +++ tests/setup-test.sh | 13 - 18 files changed, 698 insertions(+), 316 deletions(-) create mode 100644 tests/data/expected_output/GoPro_2352.mp4 create mode 100644 tests/data/expected_output/GoPro_4855.mp4 create mode 100644 tests/data/expected_output/GoPro_7322.mp4 create mode 100644 tests/data/expected_output/GoPro_7329.mp4 create mode 100644 tests/data/real_videos/GH017322.MP4 create mode 100644 tests/data/real_videos/GH017329.MP4 create mode 100644 tests/data/real_videos/GH027322.MP4 create mode 100644 tests/data/real_videos/GH027329.MP4 create mode 100644 tests/data/real_videos/GX012352.MP4 create mode 100644 tests/data/real_videos/GX014855.MP4 create mode 100644 tests/integration_test.rs delete mode 100755 tests/setup-test.sh diff --git a/.vscode/launch.json b/.vscode/launch.json index 2fb6a37..83e5dd1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,69 +1,81 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug in test", - "cargo": { - "args": [ - "build", - "--bin=gopro-chaptered-video-assembler", - "--package=gopro-chaptered-video-assembler" - ], - "filter": { - "name": "gopro-chaptered-video-assembler", - "kind": "bin" - } - }, - "args": ["-i", "tests/working_test_data", "-o", "tests/output"], - "cwd": "${workspaceFolder}", - "env": { - "RUST_BACKTRACE": "1" - } - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug in apostrophe", - "cargo": { - "args": [ - "build", - "--bin=gopro-chaptered-video-assembler", - "--package=gopro-chaptered-video-assembler" - ], - "filter": { - "name": "gopro-chaptered-video-assembler", - "kind": "bin" - } - }, - "args": ["-i", "tests/working_test_data/Test's Apostrophe", "-o", "tests/output"], - "cwd": "${workspaceFolder}", - "env": { - "RUST_BACKTRACE": "1" - } - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in executable 'gopro-chaptered-video-assembler'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=gopro-chaptered-video-assembler", - "--package=gopro-chaptered-video-assembler" - ], - "filter": { - "name": "gopro-chaptered-video-assembler", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug in test", + "cargo": { + "args": [ + "build", + "--bin=gopro-chaptered-video-assembler", + "--package=gopro-chaptered-video-assembler" + ], + "filter": { + "name": "gopro-chaptered-video-assembler", + "kind": "bin" } - ] -} \ No newline at end of file + }, + "args": [ + "--input", + "/home/alichtman/Desktop/Development/projects/gopro-chaptered-video-assembler/tests/data/real_videos", + "--output", + "/home/alichtman/Desktop/Development/projects/gopro-chaptered-video-assembler/tests/data/actual_output", + "--yes", + "--copy-single-chapter-instead-of-rename" + ], + "cwd": "${workspaceFolder}", + "env": { + "RUST_BACKTRACE": "full" + } + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug in apostrophe", + "cargo": { + "args": [ + "build", + "--bin=gopro-chaptered-video-assembler", + "--package=gopro-chaptered-video-assembler" + ], + "filter": { + "name": "gopro-chaptered-video-assembler", + "kind": "bin" + } + }, + "args": [ + "-i", + "tests/working_test_data/Test's Apostrophe", + "-o", + "tests/output" + ], + "cwd": "${workspaceFolder}", + "env": { + "RUST_BACKTRACE": "1" + } + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'gopro-chaptered-video-assembler'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=gopro-chaptered-video-assembler", + "--package=gopro-chaptered-video-assembler" + ], + "filter": { + "name": "gopro-chaptered-video-assembler", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} diff --git a/Cargo.lock b/Cargo.lock index fabaa83..1166495 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,27 +3,145 @@ version = 3 [[package]] -name = "atty" -version = "0.2.14" +name = "aho-corasick" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", ] +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "assert_cmd" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -33,110 +151,150 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "is-terminal", - "once_cell", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "atty", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] -name = "dirs" -version = "4.0.0" +name = "constant_time_eq" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] -name = "dirs-sys" -version = "0.3.7" +name = "crossbeam-deque" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "libc", - "redox_users", - "winapi", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "errno" -version = "0.2.8" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "errno-dragonfly", - "libc", - "winapi", + "crossbeam-utils", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "cc", - "libc", + "powerfmt", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.52.0", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -147,11 +305,15 @@ dependencies = [ name = "gopro-chaptered-video-assembler" version = "0.5.0" dependencies = [ + "assert_cmd", "clap", "colored", "filetime", + "fs_extra", "log", + "merkle_hash", "normpath", + "predicates", "simplelog", "uuid", "xdg", @@ -164,82 +326,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "itoa" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] -name = "hermit-abi" -version = "0.3.1" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "io-lifetimes" -version = "1.0.6" +name = "libc" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" -dependencies = [ - "libc", - "windows-sys", -] +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "is-terminal" -version = "0.4.4" +name = "log" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] -name = "itoa" -version = "1.0.6" +name = "memchr" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "merkle_hash" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "0fad8dc52477aa6f1751748a5ee1c6d50db7092e8dab1d687840dfa23e2ae4e5" +dependencies = [ + "anyhow", + "blake3", + "camino", + "rayon", +] [[package]] -name = "libc" -version = "0.2.140" +name = "normalize-line-endings" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] -name = "linux-raw-sys" -version = "0.1.4" +name = "normpath" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" +dependencies = [ + "windows-sys 0.48.0", +] [[package]] -name = "log" -version = "0.4.17" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "normpath" -version = "1.1.0" +name = "num-traits" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972dec05f98e7c787ede35d7a9ea4735eb7788c299287352757b3def6cc1f7b5" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ - "windows-sys", + "autocfg", ] [[package]] @@ -252,98 +407,136 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.17.1" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "os_str_bytes" -version = "6.4.1" +name = "predicates" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "predicates-core" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "predicates-tree" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "predicates-core", + "termtree", ] [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags", ] [[package]] -name = "redox_users" -version = "0.4.3" +name = "regex" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "rustix" -version = "0.36.9" +name = "regex-automata" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", + "aho-corasick", + "memchr", + "regex-syntax", ] +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "serde" -version = "1.0.158" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "simplelog" @@ -364,20 +557,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.10" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -394,34 +576,23 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" +name = "termtree" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.10", -] +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "time" -version = "0.3.20" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", "libc", + "num-conv", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -429,39 +600,49 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", ] [[package]] -name = "version_check" -version = "0.9.4" +name = "wait-timeout" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] [[package]] name = "wasi" @@ -487,9 +668,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -502,75 +683,138 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "xdg" -version = "2.4.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" -dependencies = [ - "dirs", -] +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" diff --git a/Cargo.toml b/Cargo.toml index 0780a0e..8a99b4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "gopro-chaptered-video-assembler" version = "0.5.0" edition = "2021" -authors = ["Aaron Lichtman"] +authors = ["Aaron Lichtman "] description = "Assembles all chaptered GoPro video files in a directory into 'complete' files." license-file = "LICENSE" homepage = "https://github.com/alichtman/gopro-chaptered-video-assembler" @@ -16,8 +16,14 @@ keywords = ["gopro", "video", "assembler", "chaptered", "ffmpeg"] clap = { version = "4.1.8", features = ["derive"] } colored = "2.0.0" filetime = "0.2.20" +fs_extra = "1.3.0" log = "0.4.17" +merkle_hash = "3.6.1" normpath = "1.1.0" simplelog = "0.12.1" uuid = { version = "1.3.0", features = ["v4"] } xdg = "2.4.1" + +[dev-dependencies] +assert_cmd = "2.0" +predicates = "3.1" diff --git a/src/cli.rs b/src/cli.rs index 42ffbef..f9cd586 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -27,9 +27,9 @@ pub struct CliArgs { /// Skips renaming single chapter videos #[arg( - short = 'n', - long = "no-single-chapter-rename", + short = 'c', + long = "copy-single-chapter-instead-of-rename", default_value = "false" )] - pub no_single_chapter_rename: bool, + pub copy_single_chapter_instead_of_renaming: bool, } diff --git a/src/main.rs b/src/main.rs index 1fc6eaa..de6bbdd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,8 +26,9 @@ fn main() { initialize_logging(); print_header(); let args = CliArgs::parse(); + print!("{:#?}", args); - // Canonicalize input path up front. We don't handle the output path until later to avoid creating the output path if the user cancels the operation. + // Canonicalize input path up front. We don't handle the output path until later to avoid creating the output path if the user cancels the operation. let input_dir = args .input .clone() @@ -35,7 +36,7 @@ fn main() { .canonicalize() .expect("Could not canonicalize input dir path. Does it exist?"); - actually_do_things_with_input_and_output_paths(input_dir, args); + actually_do_things_with_input_and_output_paths(input_dir, args); } fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliArgs) { @@ -73,7 +74,7 @@ fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliA print_expected_output( single_chapter_videos.clone(), multichapter_videos_sorted.clone(), - args.no_single_chapter_rename.clone(), + args.copy_single_chapter_instead_of_renaming.clone(), ); match get_confirmation_before_proceeeding(args.auto_confirm_yes) { true => (), @@ -90,9 +91,11 @@ fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliA args.clone(), ); - if args.no_single_chapter_rename { - info!("Skipping single chapter rename"); + if args.copy_single_chapter_instead_of_renaming { + print!("Copying single chapter videos instead of renaming"); + copy_single_chapter_videos(single_chapter_videos, output_dir, args.clone()); } else { + print!("Renaming single chapter videos"); rename_single_chapter_videos(single_chapter_videos, output_dir, args.clone()); } @@ -102,6 +105,8 @@ fn actually_do_things_with_input_and_output_paths(input_dir: PathBuf, args: CliA } } +// There's some needless code duplication here. Could be cleaner + fn rename_single_chapter_videos( single_chapter_videos: std::collections::HashMap>, output_dir: PathBuf, @@ -124,3 +129,26 @@ fn rename_single_chapter_videos( } } } + +fn copy_single_chapter_videos( + single_chapter_videos: std::collections::HashMap>, + output_dir: PathBuf, + args: CliArgs, +) { + for video in single_chapter_videos { + let video_number = video.0; + let video_path = video.1[0].abs_path.clone(); + let output_path = gen_output_path(&output_dir, video_number, "mp4"); + info!( + "Copying {} to {}", + video_path.to_string_lossy().green().bold(), + output_path.to_string_lossy().blue().bold() + ); + if args.dry_run { + info!("Dry run, skipping copy!"); + continue; + } else { + std::fs::copy(video_path, output_path).expect("Failed to copy file"); + } + } +} diff --git a/src/printing.rs b/src/printing.rs index 5412026..1ac2e01 100644 --- a/src/printing.rs +++ b/src/printing.rs @@ -45,7 +45,7 @@ pub fn get_confirmation_before_proceeeding(skip_confirmation: bool) -> bool { pub fn print_expected_output( single_chapter_videos: std::collections::HashMap>, multichapter_videos_sorted: std::collections::HashMap>, - no_single_chapter_rename: bool, + copy_single_chapter_instead_of_renaming: bool, ) { let mut total_chapters_to_combine = 0; let total_videos_to_output = multichapter_videos_sorted.len(); @@ -60,9 +60,9 @@ pub fn print_expected_output( if total_videos_to_output > 0 { info!("{:#?}", multichapter_videos_sorted); } - if no_single_chapter_rename { + if copy_single_chapter_instead_of_renaming { info!( - "Skipping renaming of {} single chapter video(s)", + "And {} single chapter video(s) to copy", single_chapter_videos.len().to_string().blue().bold() ); } else { @@ -78,7 +78,12 @@ pub fn print_expected_output( pub fn print_remove_commands( multichapter_videos: std::collections::HashMap>, ) { - println!("{}", "Run the following command(s) to remove the merged chapters".yellow().bold()); + println!( + "{}", + "Run the following command(s) to remove the merged chapters" + .yellow() + .bold() + ); for (_key, chapters) in multichapter_videos { for chapter in chapters { println!("rm '{}'", chapter.abs_path.to_str().unwrap().blue().bold()); diff --git a/tests/data/expected_output/GoPro_2352.mp4 b/tests/data/expected_output/GoPro_2352.mp4 new file mode 100644 index 0000000..a8801cc --- /dev/null +++ b/tests/data/expected_output/GoPro_2352.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8332113edf2b3cf15319a863a5858093cc53b1149a225d9e742a3ea28937185 +size 136038059 diff --git a/tests/data/expected_output/GoPro_4855.mp4 b/tests/data/expected_output/GoPro_4855.mp4 new file mode 100644 index 0000000..4d69c2e --- /dev/null +++ b/tests/data/expected_output/GoPro_4855.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93ea737d2e3c5f4422b2019eb9d84e701fa0a4fe96ee552dcd3f59a9882f6a68 +size 61789453 diff --git a/tests/data/expected_output/GoPro_7322.mp4 b/tests/data/expected_output/GoPro_7322.mp4 new file mode 100644 index 0000000..74d75e0 --- /dev/null +++ b/tests/data/expected_output/GoPro_7322.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b72216e88c86f5a143c13a3df0926b66d9039550d5edf7d259bacaac44225870 +size 652853591 diff --git a/tests/data/expected_output/GoPro_7329.mp4 b/tests/data/expected_output/GoPro_7329.mp4 new file mode 100644 index 0000000..91bcad4 --- /dev/null +++ b/tests/data/expected_output/GoPro_7329.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67401b0fa2219bebb8813f7718952cfe13eac579298a17c366905bc55b2e8bfe +size 381247351 diff --git a/tests/data/real_videos/GH017322.MP4 b/tests/data/real_videos/GH017322.MP4 new file mode 100644 index 0000000..e451744 --- /dev/null +++ b/tests/data/real_videos/GH017322.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a7d889207b32c0064b682bd30618b6dd845a13ffd2b3b1b150c0cbc9b2db6e4 +size 231805343 diff --git a/tests/data/real_videos/GH017329.MP4 b/tests/data/real_videos/GH017329.MP4 new file mode 100644 index 0000000..7299b69 --- /dev/null +++ b/tests/data/real_videos/GH017329.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:961b165b120dd708e6430144a14ce448d882a2c1edebd86f51ed3aec1b88f9c1 +size 129846626 diff --git a/tests/data/real_videos/GH027322.MP4 b/tests/data/real_videos/GH027322.MP4 new file mode 100644 index 0000000..e02c55f --- /dev/null +++ b/tests/data/real_videos/GH027322.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9daed89e05168f95414824c84af036334894ba57d0ec512155fae7e949612928 +size 421041915 diff --git a/tests/data/real_videos/GH027329.MP4 b/tests/data/real_videos/GH027329.MP4 new file mode 100644 index 0000000..5345976 --- /dev/null +++ b/tests/data/real_videos/GH027329.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b57e4e08094b677b8f6ec525668a37c401c3fde95aef8faa7113de54b51918c +size 251395360 diff --git a/tests/data/real_videos/GX012352.MP4 b/tests/data/real_videos/GX012352.MP4 new file mode 100644 index 0000000..a8801cc --- /dev/null +++ b/tests/data/real_videos/GX012352.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8332113edf2b3cf15319a863a5858093cc53b1149a225d9e742a3ea28937185 +size 136038059 diff --git a/tests/data/real_videos/GX014855.MP4 b/tests/data/real_videos/GX014855.MP4 new file mode 100644 index 0000000..4d69c2e --- /dev/null +++ b/tests/data/real_videos/GX014855.MP4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93ea737d2e3c5f4422b2019eb9d84e701fa0a4fe96ee552dcd3f59a9882f6a68 +size 61789453 diff --git a/tests/integration_test.rs b/tests/integration_test.rs new file mode 100644 index 0000000..7599602 --- /dev/null +++ b/tests/integration_test.rs @@ -0,0 +1,70 @@ +use assert_cmd::prelude::*; +use merkle_hash::{Algorithm, Encodable, MerkleTree}; +use std::path::PathBuf; +use std::process::Command; + +extern crate fs_extra; +use std::fs; + +pub(crate) fn get_hash_of_directory(dir: &PathBuf) -> Vec { + let tree = MerkleTree::builder(dir.to_str().unwrap()) + .algorithm(Algorithm::Blake3) + .hash_names(false) + .build() + .unwrap(); + let master_hash = tree.root.item.hash; + master_hash +} + +pub(crate) fn get_path_to_source_videos() -> PathBuf { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("tests/data/real_videos"); + path +} + +pub(crate) fn get_path_to_test_output() -> PathBuf { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("tests/data/actual_output"); + path +} + +pub(crate) fn get_path_to_expected_output() -> PathBuf { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("tests/data/expected_output"); + path +} + +pub(crate) fn setup() { + self::teardown(); + let _ = fs::create_dir(get_path_to_test_output()); +} + +pub(crate) fn teardown() { + for entry in vec![get_path_to_test_output()] { + let _ = fs::remove_dir_all(entry); + } +} + +#[test] +fn test_run_on_dir() { + self::setup(); + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); + cmd.arg("--input") + .arg(get_path_to_source_videos()) + .arg("--output") + .arg(get_path_to_test_output()) + .arg("--yes") + .arg("--copy-single-chapter-instead-of-rename"); + let output = cmd.unwrap(); + print!("{:#?}", output); + // Check that actual_output matches expected_output + let expected_output_hash = get_hash_of_directory(&get_path_to_expected_output()); + let actual_output_hash = get_hash_of_directory(&get_path_to_test_output()); + assert!(expected_output_hash == actual_output_hash); + print!( + "\n{:#?} was the merkle hash for both the expected and actual", + expected_output_hash.to_hex_string() + ); + + self::teardown(); +} diff --git a/tests/setup-test.sh b/tests/setup-test.sh deleted file mode 100755 index 57cf048..0000000 --- a/tests/setup-test.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Exit if not in git root -if [ ! -d .git ]; then - echo "Not in git root" - exit 1 -fi - -rm -rf tests/output tests/working_test_data -mkdir tests/working_test_data -mkdir "tests/working_test_data/Test\'s Apostrophe" -cp -vp tests/real_videos/* tests/working_test_data/ -cp -vp tests/real_videos/* "tests/working_test_data/Test\'s Apostrophe" From a712a2784fbacc7dda69ada016ee39cb02813401 Mon Sep 17 00:00:00 2001 From: Aaron Lichtman Date: Tue, 6 Feb 2024 05:56:35 -0800 Subject: [PATCH 5/5] Pass test? --- src/ffmpeg.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ffmpeg.rs b/src/ffmpeg.rs index 1a8f968..19f4838 100644 --- a/src/ffmpeg.rs +++ b/src/ffmpeg.rs @@ -46,7 +46,11 @@ pub fn concatenate_mp4s_from_demuxer_file( info!("Dry run, skipping ffmpeg command!"); return; } - let output = command.spawn().unwrap().wait_with_output().unwrap(); + let output = command + .spawn() + .expect("Command failed to run") + .wait_with_output() + .expect("Command output failed to be collected"); // if ffmpeg doesn't run successfully, scream and die if !output.status.success() {