From e1f33b58fac4299a434285a35fd6bdc9cae5d96c Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Wed, 14 Jan 2026 19:12:57 +0000 Subject: [PATCH] feat: add sort_perf_log --- Cargo.lock | 7 + Cargo.toml | 1 + copy_random_files/Cargo.lock | 408 +++++++++++++++++++++++++++++++++++ sort_perf_log/CLAUDE.md | 11 + sort_perf_log/Cargo.toml | 12 ++ sort_perf_log/src/CLAUDE.md | 12 ++ sort_perf_log/src/main.rs | 221 +++++++++++++++++++ 7 files changed, 672 insertions(+) create mode 100644 copy_random_files/Cargo.lock create mode 100644 sort_perf_log/CLAUDE.md create mode 100644 sort_perf_log/Cargo.toml create mode 100644 sort_perf_log/src/CLAUDE.md create mode 100644 sort_perf_log/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 55fb935..376544f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2744,6 +2744,13 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "sort_perf_log" +version = "0.1.0" +dependencies = [ + "regex", +] + [[package]] name = "spki" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index c6f0356..8c592cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "find_log_processtime", "archive_dirs", "s3_bucket_downloader", + "sort_perf_log", # Add other tools here ] resolver = "2" diff --git a/copy_random_files/Cargo.lock b/copy_random_files/Cargo.lock new file mode 100644 index 0000000..46c527d --- /dev/null +++ b/copy_random_files/Cargo.lock @@ -0,0 +1,408 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "copy_random_files" +version = "0.1.0" +dependencies = [ + "clap", + "indicatif", + "rand", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/sort_perf_log/CLAUDE.md b/sort_perf_log/CLAUDE.md new file mode 100644 index 0000000..68ee27c --- /dev/null +++ b/sort_perf_log/CLAUDE.md @@ -0,0 +1,11 @@ + +# Recent Activity + + + +### Jan 14, 2026 + +| ID | Time | T | Title | Read | +|----|------|---|-------|------| +| #1214 | 7:00 PM | 🟣 | Rust Implementation Started for Performance Log Parser | ~300 | + diff --git a/sort_perf_log/Cargo.toml b/sort_perf_log/Cargo.toml new file mode 100644 index 0000000..ec1247c --- /dev/null +++ b/sort_perf_log/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "sort_perf_log" +version = "0.1.0" +edition = "2021" +description = "Parse and sort video processing performance logs by total processing time" + +[dependencies] +regex = "1" + +[profile.release] +opt-level = 3 +lto = true diff --git a/sort_perf_log/src/CLAUDE.md b/sort_perf_log/src/CLAUDE.md new file mode 100644 index 0000000..b9f2e10 --- /dev/null +++ b/sort_perf_log/src/CLAUDE.md @@ -0,0 +1,12 @@ + +# Recent Activity + + + +### Jan 14, 2026 + +| ID | Time | T | Title | Read | +|----|------|---|-------|------| +| #1216 | 7:09 PM | ✅ | Applied automated Rust code formatting across project | ~256 | +| #1215 | " | 🔴 | Fixed cargo fmt formatting violations in Rust CLI tool | ~312 | + diff --git a/sort_perf_log/src/main.rs b/sort_perf_log/src/main.rs new file mode 100644 index 0000000..f732600 --- /dev/null +++ b/sort_perf_log/src/main.rs @@ -0,0 +1,221 @@ +use regex::Regex; +use std::collections::HashMap; +use std::env; +use std::fs; +use std::io::{self, BufRead, Write}; + +#[derive(Default, Debug)] +struct VideoMetrics { + scene_detect_fps: Option, + scene_detect_time: Option, + ocr_fps: Option, + ocr_time: Option, + logo_detect_images: Option, + logo_detect_fps: Option, + logo_detect_time: Option, + object_detect_images: Option, + object_detect_fps: Option, + object_detect_time: Option, + transcribe_time: Option, + scene_description_time: Option, + process_video_time: Option, +} + +fn fmt_float(val: Option, suffix: &str) -> String { + match val { + Some(v) => format!("{:.1}{}", v, suffix), + None => "-".to_string(), + } +} + +fn fmt_int(val: Option) -> String { + match val { + Some(v) => v.to_string(), + None => "-".to_string(), + } +} + +fn main() -> io::Result<()> { + let args: Vec = env::args().collect(); + + if args.len() < 3 { + eprintln!("Usage: {} ", args[0]); + eprintln!( + "Example: {} 20260113-all-perf.log 20260113-all-perf-sorted.log", + args[0] + ); + std::process::exit(1); + } + + let input_file = &args[1]; + let output_file = &args[2]; + + // Compile regex patterns + let summary_re = Regex::new(r"Performance Summary of (input_files/\S+):").unwrap(); + let scene_detect_re = + Regex::new(r"func=scene_detect\s+file=\S+\s+fps=([\d.]+)\s+time=([\d.]+)s").unwrap(); + let ocr_re = Regex::new(r"func=ocr\s+file=\S+\s+fps=([\d.]+)\s+time=([\d.]+)s").unwrap(); + let logo_detect_re = + Regex::new(r"func=logo_detect\s+images=(\d+)\s+fps=([\d.]+)\s+time=([\d.]+)s").unwrap(); + let object_detect_re = + Regex::new(r"func=object_detect\s+images=(\d+)\s+fps=([\d.]+)\s+time=([\d.]+)s").unwrap(); + let transcribe_re = Regex::new(r"func=transcribe\s+file=\S+\s+time=([\d.]+)s").unwrap(); + let scene_desc_re = Regex::new(r"func=scene_description\s+file=\S+\s+time=([\d.]+)s").unwrap(); + let process_video_re = Regex::new(r"func=process_video\s+file=\S+\s+time=([\d.]+)s").unwrap(); + + // Parse the log file + let file = fs::File::open(input_file)?; + let reader = io::BufReader::new(file); + + let mut videos: HashMap = HashMap::new(); + let mut current_video: Option = None; + + for line in reader.lines() { + let line = line?; + + // Check for Performance Summary line + if let Some(caps) = summary_re.captures(&line) { + let full_path = caps.get(1).unwrap().as_str(); + let video_id = full_path.replace("input_files/", ""); + current_video = Some(video_id.clone()); + videos.entry(video_id).or_default(); + continue; + } + + // Parse performance metrics + if let Some(ref video_id) = current_video { + if !line.contains("[PERF]") { + continue; + } + + let metrics = videos.get_mut(video_id).unwrap(); + + if let Some(caps) = scene_detect_re.captures(&line) { + metrics.scene_detect_fps = caps.get(1).and_then(|m| m.as_str().parse().ok()); + metrics.scene_detect_time = caps.get(2).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = ocr_re.captures(&line) { + metrics.ocr_fps = caps.get(1).and_then(|m| m.as_str().parse().ok()); + metrics.ocr_time = caps.get(2).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = logo_detect_re.captures(&line) { + metrics.logo_detect_images = caps.get(1).and_then(|m| m.as_str().parse().ok()); + metrics.logo_detect_fps = caps.get(2).and_then(|m| m.as_str().parse().ok()); + metrics.logo_detect_time = caps.get(3).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = object_detect_re.captures(&line) { + metrics.object_detect_images = caps.get(1).and_then(|m| m.as_str().parse().ok()); + metrics.object_detect_fps = caps.get(2).and_then(|m| m.as_str().parse().ok()); + metrics.object_detect_time = caps.get(3).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = transcribe_re.captures(&line) { + metrics.transcribe_time = caps.get(1).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = scene_desc_re.captures(&line) { + metrics.scene_description_time = caps.get(1).and_then(|m| m.as_str().parse().ok()); + continue; + } + + if let Some(caps) = process_video_re.captures(&line) { + metrics.process_video_time = caps.get(1).and_then(|m| m.as_str().parse().ok()); + continue; + } + } + } + + // Sort videos by process_video_time (descending) + let mut sorted_videos: Vec<(&String, &VideoMetrics)> = videos + .iter() + .filter(|(_, m)| m.process_video_time.is_some()) + .collect(); + + sorted_videos.sort_by(|a, b| { + b.1.process_video_time + .partial_cmp(&a.1.process_video_time) + .unwrap_or(std::cmp::Ordering::Equal) + }); + + // Generate output + let mut output = fs::File::create(output_file)?; + + writeln!( + output, + "# Video Processing Performance Report (Sorted by Total Time)" + )?; + writeln!(output)?; + writeln!(output, "Total videos processed: {}", sorted_videos.len())?; + writeln!(output)?; + writeln!(output, "| # | Video ID | scene_detect (fps/time) | ocr (fps/time) | logo_detect (imgs/fps/time) | object_detect (imgs/fps/time) | transcribe | scene_desc | total |")?; + writeln!(output, "|---|----------|-------------------------|----------------|------------------------------|-------------------------------|------------|------------|-------|")?; + + for (i, (vid, data)) in sorted_videos.iter().enumerate() { + let scene_d = format!( + "{}/{}", + fmt_float(data.scene_detect_fps, ""), + fmt_float(data.scene_detect_time, "s") + ); + let ocr = format!( + "{}/{}", + fmt_float(data.ocr_fps, ""), + fmt_float(data.ocr_time, "s") + ); + let logo = format!( + "{}/{}/{}", + fmt_int(data.logo_detect_images), + fmt_float(data.logo_detect_fps, ""), + fmt_float(data.logo_detect_time, "s") + ); + let obj = format!( + "{}/{}/{}", + fmt_int(data.object_detect_images), + fmt_float(data.object_detect_fps, ""), + fmt_float(data.object_detect_time, "s") + ); + let trans = fmt_float(data.transcribe_time, "s"); + let scene_desc = fmt_float(data.scene_description_time, "s"); + let total = fmt_float(data.process_video_time, "s"); + + writeln!( + output, + "| {} | {} | {} | {} | {} | {} | {} | {} | {} |", + i + 1, + vid, + scene_d, + ocr, + logo, + obj, + trans, + scene_desc, + total + )?; + } + + println!("Output written to {}", output_file); + println!("Total videos: {}", sorted_videos.len()); + if let Some((first_vid, first_data)) = sorted_videos.first() { + println!( + "Longest: {} at {:.1}s", + first_vid, + first_data.process_video_time.unwrap_or(0.0) + ); + } + if let Some((last_vid, last_data)) = sorted_videos.last() { + println!( + "Shortest: {} at {:.1}s", + last_vid, + last_data.process_video_time.unwrap_or(0.0) + ); + } + + Ok(()) +}