From 8eafec7fd29c43b7e8a17d867a404cdead1b6d1b Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 24 Nov 2019 11:01:46 -0800 Subject: [PATCH] Collapse multipart movies into single Movie entity. --- Cargo.lock | 135 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++ src/lib.rs | 63 ++++++++++-------- src/movielibrary_test.rs | 135 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 311 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35b0e59..4c06a2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,14 @@ name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.46" @@ -137,6 +145,20 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ctor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "either" version = "1.5.3" @@ -162,6 +184,16 @@ dependencies = [ "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.3.0" @@ -263,6 +295,30 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "output_vt100" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pretty_assertions" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro-error" version = "0.2.6" @@ -294,6 +350,43 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.2.0" @@ -337,6 +430,14 @@ name = "regex-syntax" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" version = "0.1.16" @@ -448,6 +549,7 @@ dependencies = [ "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", @@ -455,6 +557,7 @@ dependencies = [ "stderrlog 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tabwriter 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -486,6 +589,19 @@ dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "0.3.6" @@ -540,6 +656,11 @@ name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.8" @@ -576,6 +697,7 @@ dependencies = [ "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" @@ -584,9 +706,12 @@ dependencies = [ "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" +"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" @@ -602,15 +727,23 @@ dependencies = [ "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" +"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" @@ -627,6 +760,7 @@ dependencies = [ "checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tabwriter 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9128e3a9149e51494cad59712a286e149fcb74e443d2298d69bd6eaa42cc4ebb" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" @@ -635,6 +769,7 @@ dependencies = [ "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 717fdae..1fdba4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,7 @@ serde_json = "1" stderrlog = "0.4" structopt = "0.3" tabwriter = "1" + +[dev-dependencies] +pretty_assertions = "0.6.1" +tempfile = "3.1.0" diff --git a/src/lib.rs b/src/lib.rs index 641de47..c44e7a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::collections::HashSet; use std::env; use std::ffi::OsStr; use std::fmt; @@ -34,6 +33,12 @@ const COMPACT_METADATA_FILENAME: &str = "metadata.compact.json"; #[derive(Clone, Deserialize, Debug, PartialEq, Serialize)] pub struct Resolution(usize, usize); +impl From<(usize, usize)> for Resolution { + fn from(res: (usize, usize)) -> Self { + Resolution(res.0, res.1) + } +} + impl Display for Resolution { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let v = format!("{}x{}", self.0, self.1); @@ -61,19 +66,22 @@ where T::from_str(&s).map_err(de::Error::custom) } -pub fn is_multidisc(names: &Vec) -> bool { - // TODO(wathiede): smarter version that helps with: - // The Hudsucker Proxy: - // 1920x1080 4.78Gi 1h 50m 45s 54151c3b9a2a4773958f848efecefc3b.mkv - // 720x416 736.51Mi 50m 40s The Hudsucker Proxy CD1.avi - // 720x416 736.49Mi 1h 3s The Hudsucker Proxy CD2.avi +fn collapse_multidisc(names: &Vec) -> HashMap> { lazy_static! { static ref DIGIT: Regex = Regex::new("[0-9]").unwrap(); } - let mut set = HashSet::new(); + let mut set = HashMap::new(); for name in names { - set.insert(DIGIT.replace_all(&name, "#").to_string()); + let clean = DIGIT.replace_all(&name, "#").to_string(); + set.entry(clean) + .or_insert(Vec::new()) + .push(name.to_string()); } + set +} + +pub fn is_multidisc(names: &Vec) -> bool { + let set = collapse_multidisc(names); set.len() == 1 } @@ -282,7 +290,7 @@ lazy_static! { static ref MOVIE_EXTS: Vec<&'static str> = vec!["avi", "m4v", "mkv", "mov", "mp4"]; } -#[derive(Debug, PartialEq)] +#[derive(Default, Debug, PartialEq)] struct Movie { files: Vec<(String, CompactMetadata)>, } @@ -292,22 +300,29 @@ pub struct Movies { movies: Vec, } -fn movies_from_paths_compact_metadata(p_cmd: HashMap) -> Movies { - // file path - let files_to_movies: HashMap> = HashMap::new(); - // TODO(wathiede): - // - walk over every item, use something based on is_multidisc to pack multifile movies - // together. - // - then walk over `files` and create a Movie for each - // - then store those Movie structs in Movies - - let movies = p_cmd +fn movies_from_paths_compact_metadata(mut p_cmd: HashMap) -> Movies { + let multidisc = collapse_multidisc(&p_cmd.keys().map(|s| s.to_string()).collect()); + let movies = multidisc .into_iter() - .map(|(p, cmd)| Movie { - files: vec![(p, cmd)], + .map(|(_hash, names)| { + let mut files: Vec<(String, CompactMetadata)> = names + .iter() + .map(|name| (name.to_string(), p_cmd.remove(name).unwrap())) + .collect(); + files.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + Movie { files } }) .collect(); - Movies { movies } + let mut m = Movies { movies }; + m.movies.sort_by(|a, b| { + a.files + .first() + .unwrap() + .0 + .partial_cmp(&b.files.first().unwrap().0) + .unwrap() + }); + m } impl MovieLibrary { @@ -504,7 +519,6 @@ impl MovieLibrary { pub fn movies(&self) -> Result { let path = Path::new(&self.root).join(COMPACT_METADATA_FILENAME); - // Open the file in read-only mode with buffer. let f = File::open(&path).context(format!("open {}", path.display()))?; let r = BufReader::new(f); @@ -515,7 +529,6 @@ impl MovieLibrary { pub fn videos(&self) -> Result<(HashMap), Error> { let path = Path::new(&self.root).join(COMPACT_METADATA_FILENAME); - // Open the file in read-only mode with buffer. let f = File::open(&path).context(format!("open {}", path.display()))?; let r = BufReader::new(f); diff --git a/src/movielibrary_test.rs b/src/movielibrary_test.rs index 9bb80cb..ee54147 100644 --- a/src/movielibrary_test.rs +++ b/src/movielibrary_test.rs @@ -1,3 +1,8 @@ +use std::error::Error; + +use pretty_assertions::assert_eq; +use tempfile::tempdir; + use super::*; #[allow(dead_code)] @@ -6,7 +11,7 @@ fn testdata_dir() -> PathBuf { } #[test] -fn test_library() { +fn test_simple_library() { let ml = MovieLibrary::new(testdata_dir().join("simple").to_str().unwrap()); assert_eq!( ml.movies().expect("failed to build movies"), @@ -43,3 +48,131 @@ fn test_library() { } ); } + +fn build_tuple(path: &str, res: R) -> (String, CompactMetadata) +where + R: Into, +{ + let res = res.into(); + ( + path.to_string(), + CompactMetadata { + filename: format!("./{}", path), + bit_rate: 1, + duration: 1.0, + format_name: "test_format".to_string(), + size: 1, + video: vec![VideoFormat { + width: res.0, + height: res.1, + ..Default::default() + }], + ..Default::default() + }, + ) +} + +fn build_movie(paths: Vec<(&str, R)>) -> Movie +where + R: Into, +{ + Movie { + files: paths + .into_iter() + .map(|(path, res)| build_tuple(path, res)) + .collect(), + } +} + +fn build_complex_metadata() -> HashMap { + vec![ + build_tuple( + "One Movie With Year (2019)/abcdef123456789.mkv", + (1920, 1080), + ), + build_tuple( + "One Movie With Two Parts (2019)/abcdef123456789 part 1.mkv", + (1280, 720), + ), + build_tuple( + "One Movie With Two Parts (2019)/abcdef123456789 part 2.mkv", + (1280, 720), + ), + build_tuple( + "Two Movies With Multi Parts (2019)/abcdef123456789 part 1.mkv", + (1280, 720), + ), + build_tuple( + "Two Movies With Multi Parts (2019)/abcdef123456789 part 2.mkv", + (1280, 720), + ), + build_tuple( + "Two Movies With Multi Parts (2019)/somethingelse.mkv", + (1920, 1080), + ), + ] + .into_iter() + .collect() +} + +fn build_complex_movies() -> Movies { + let mut m = Movies { + movies: vec![ + build_movie(vec![( + "One Movie With Year (2019)/abcdef123456789.mkv", + (1920, 1080), + )]), + build_movie(vec![ + ( + "One Movie With Two Parts (2019)/abcdef123456789 part 1.mkv", + (1280, 720), + ), + ( + "One Movie With Two Parts (2019)/abcdef123456789 part 2.mkv", + (1280, 720), + ), + ]), + build_movie(vec![ + ( + "Two Movies With Multi Parts (2019)/abcdef123456789 part 1.mkv", + (1280, 720), + ), + ( + "Two Movies With Multi Parts (2019)/abcdef123456789 part 2.mkv", + (1280, 720), + ), + ]), + build_movie(vec![( + "Two Movies With Multi Parts (2019)/somethingelse.mkv", + (1920, 1080), + )]), + ], + }; + m.movies.sort_by(|a, b| { + a.files + .first() + .unwrap() + .0 + .partial_cmp(&b.files.first().unwrap().0) + .unwrap() + }); + m +} + +#[test] +fn test_roundtrip_library() -> Result<(), Box> { + let metadata = build_complex_metadata(); + let want = build_complex_movies(); + let dir = tempdir()?; + let path = dir.path().join(COMPACT_METADATA_FILENAME); + let f = File::create(path.to_str().unwrap().to_string()).expect("failed to save"); + let f = BufWriter::new(f); + serde_json::ser::to_writer_pretty(f, &metadata)?; + + let ml = MovieLibrary::new(dir.path().to_str().unwrap().to_string()); + let got = ml.movies().expect("failed to build movies"); + assert_eq!(got.movies.len(), want.movies.len()); + assert_eq!(got, want); + //assert_eq!(got, want, "Got {:#?}\nWant {:#?}", got, want); + Ok(()) +}