diff --git a/Cargo.lock b/Cargo.lock index f205883..a7432c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "async-trait" @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.29" +version = "4.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" +checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2" dependencies = [ "bitflags", "clap_derive", @@ -212,6 +212,20 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size 0.1.17", + "unicode-width", + "winapi", +] + [[package]] name = "cookie" version = "0.16.2" @@ -288,6 +302,7 @@ dependencies = [ "csv", "ctrlc", "dirs", + "indicatif", "log", "num_cpus", "regex", @@ -297,7 +312,7 @@ dependencies = [ "signal-hook", "sys-locale", "tempfile", - "terminal_size", + "terminal_size 0.2.3", "tokio", ] @@ -379,9 +394,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -391,9 +406,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -406,15 +421,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", @@ -476,6 +491,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.31" @@ -645,15 +666,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -808,6 +820,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4295cbb7573c16d310e99e713cf9e75101eb190ab31fccd35f2d2691b4352b19" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "inout" version = "0.1.3" @@ -845,11 +869,11 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "io-lifetimes", "rustix", "windows-sys 0.42.0", @@ -1019,14 +1043,20 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.16.0" @@ -1035,9 +1065,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "openssl" -version = "0.10.44" +version = "0.10.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" dependencies = [ "bitflags", "cfg-if", @@ -1067,9 +1097,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.79" +version = "0.9.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" dependencies = [ "autocfg", "cc", @@ -1108,6 +1138,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "portable-atomic" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1134,15 +1170,15 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.19" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -1165,9 +1201,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1412,9 +1448,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa 1.0.5", "ryu", @@ -1502,9 +1538,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1547,6 +1583,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "terminal_size" version = "0.2.3" diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock index a85defe..8347aa7 100644 --- a/crunchy-cli-core/Cargo.lock +++ b/crunchy-cli-core/Cargo.lock @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "async-trait" @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.29" +version = "4.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" +checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2" dependencies = [ "bitflags", "clap_derive", @@ -193,6 +193,20 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size 0.1.17", + "unicode-width", + "winapi", +] + [[package]] name = "cookie" version = "0.16.2" @@ -257,6 +271,7 @@ dependencies = [ "csv", "ctrlc", "dirs", + "indicatif", "log", "num_cpus", "regex", @@ -266,7 +281,7 @@ dependencies = [ "signal-hook", "sys-locale", "tempfile", - "terminal_size", + "terminal_size 0.2.3", "tokio", ] @@ -348,9 +363,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -360,9 +375,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -375,15 +390,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", @@ -445,6 +460,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.31" @@ -614,15 +635,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -777,6 +789,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4295cbb7573c16d310e99e713cf9e75101eb190ab31fccd35f2d2691b4352b19" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "inout" version = "0.1.3" @@ -814,11 +838,11 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "io-lifetimes", "rustix", "windows-sys 0.42.0", @@ -988,14 +1012,20 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.16.0" @@ -1004,9 +1034,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "openssl" -version = "0.10.44" +version = "0.10.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" dependencies = [ "bitflags", "cfg-if", @@ -1036,9 +1066,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.79" +version = "0.9.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" dependencies = [ "autocfg", "cc", @@ -1077,6 +1107,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "portable-atomic" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1103,15 +1139,15 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.19" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -1134,9 +1170,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1375,9 +1411,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa 1.0.5", "ryu", @@ -1465,9 +1501,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1510,6 +1546,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "terminal_size" version = "0.2.3" diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml index 6dccd4d..780716f 100644 --- a/crunchy-cli-core/Cargo.toml +++ b/crunchy-cli-core/Cargo.toml @@ -13,6 +13,7 @@ crunchyroll-rs = "0.2" csv = "1.1" ctrlc = "3.2" dirs = "4.0" +indicatif = "0.17" log = { version = "0.4", features = ["std"] } num_cpus = "1.14" regex = "1.7" diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs index 6e56e81..b5244f7 100644 --- a/crunchy-cli-core/src/cli/archive.rs +++ b/crunchy-cli-core/src/cli/archive.rs @@ -1,5 +1,5 @@ use crate::cli::log::tab_info; -use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution}; +use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset}; use crate::utils::context::Context; use crate::utils::format::{format_string, Format}; use crate::utils::log::progress; @@ -137,7 +137,9 @@ impl Execute for Archive { bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported") } let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?; - if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia { + if self.ffmpeg_preset.len() == 1 + && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia + { warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified") } @@ -148,20 +150,20 @@ impl Execute for Archive { let mut parsed_urls = vec![]; for (i, url) in self.urls.iter().enumerate() { - let _progress_handler = progress!("Parsing url {}", i + 1); + let progress_handler = progress!("Parsing url {}", i + 1); match parse_url(&ctx.crunchy, url.clone(), true).await { Ok((media_collection, url_filter)) => { parsed_urls.push((media_collection, url_filter)); - info!("Parsed url {}", i + 1) + progress_handler.stop(format!("Parsed url {}", i + 1)) } Err(e) => bail!("url {} could not be parsed: {}", url, e), } } for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() { + let progress_handler = progress!("Fetching series details"); let archive_formats = match media_collection { MediaCollection::Series(series) => { - let _progress_handler = progress!("Fetching series details"); formats_from_series(&self, series, &url_filter).await? } MediaCollection::Season(_) => bail!("Archiving a season is not supported"), @@ -171,10 +173,13 @@ impl Execute for Archive { }; if archive_formats.is_empty() { - info!("Skipping url {} (no matching episodes found)", i + 1); + progress_handler.stop(format!( + "Skipping url {} (no matching episodes found)", + i + 1 + )); continue; } - info!("Loaded series information for url {}", i + 1); + progress_handler.stop(format!("Loaded series information for url {}", i + 1)); if log::max_level() == log::Level::Debug { let seasons = sort_formats_after_seasons( @@ -310,9 +315,9 @@ impl Execute for Archive { )) } - let _progess_handler = progress!("Generating mkv"); + let progess_handler = progress!("Generating mkv"); generate_mkv(&self, path, video_paths, audio_paths, subtitle_paths)?; - info!("Mkv generated") + progess_handler.stop("Mkv generated") } } @@ -349,7 +354,10 @@ async fn formats_from_series( // remove all seasons with the wrong audio for the current iterated season number seasons.retain(|s| { s.metadata.season_number != season.first().unwrap().metadata.season_number - || archive.locale.iter().any(|l| s.metadata.audio_locales.contains(l)) + || archive + .locale + .iter() + .any(|l| s.metadata.audio_locales.contains(l)) }) } @@ -358,7 +366,10 @@ async fn formats_from_series( BTreeMap::new(); for season in series.seasons().await? { if !url_filter.is_season_valid(season.metadata.season_number) - || !archive.locale.iter().any(|l| season.metadata.audio_locales.contains(l)) + || !archive + .locale + .iter() + .any(|l| season.metadata.audio_locales.contains(l)) { continue; } diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs index 4e4eb3c..d8a4ada 100644 --- a/crunchy-cli-core/src/cli/download.rs +++ b/crunchy-cli-core/src/cli/download.rs @@ -1,5 +1,5 @@ use crate::cli::log::tab_info; -use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution}; +use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset}; use crate::utils::context::Context; use crate::utils::format::{format_string, Format}; use crate::utils::log::progress; @@ -92,7 +92,9 @@ impl Execute for Download { } let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?; - if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia { + if self.ffmpeg_preset.len() == 1 + && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia + { warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified") } @@ -103,18 +105,18 @@ impl Execute for Download { let mut parsed_urls = vec![]; for (i, url) in self.urls.iter().enumerate() { - let _progress_handler = progress!("Parsing url {}", i + 1); + let progress_handler = progress!("Parsing url {}", i + 1); match parse_url(&ctx.crunchy, url.clone(), true).await { Ok((media_collection, url_filter)) => { parsed_urls.push((media_collection, url_filter)); - info!("Parsed url {}", i + 1) + progress_handler.stop(format!("Parsed url {}", i + 1)) } Err(e) => bail!("url {} could not be parsed: {}", url, e), } } for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() { - let _progress_handler = progress!("Fetching series details"); + let progress_handler = progress!("Fetching series details"); let formats = match media_collection { MediaCollection::Series(series) => { debug!("Url {} is series ({})", i + 1, series.title); @@ -156,11 +158,10 @@ impl Execute for Download { }; let Some(formats) = formats else { - info!("Skipping url {} (no matching episodes found)", i + 1); + progress_handler.stop(format!("Skipping url {} (no matching episodes found)", i + 1)); continue; }; - info!("Loaded series information for url {}", i + 1); - drop(_progress_handler); + progress_handler.stop(format!("Loaded series information for url {}", i + 1)); if log::max_level() == log::Level::Debug { let seasons = sort_formats_after_seasons(formats.clone()); @@ -231,7 +232,9 @@ impl Execute for Download { tab_info!("Resolution: {}", format.stream.resolution); tab_info!("FPS: {:.2}", format.stream.fps); - if path.extension().unwrap_or_default().to_string_lossy() != "ts" || !self.ffmpeg_preset.is_empty() { + if path.extension().unwrap_or_default().to_string_lossy() != "ts" + || !self.ffmpeg_preset.is_empty() + { download_ffmpeg(&ctx, &self, format.stream, path.as_path()).await?; } else if path.to_str().unwrap() == "-" { let mut stdout = std::io::stdout().lock(); @@ -247,7 +250,12 @@ impl Execute for Download { } } -async fn download_ffmpeg(ctx: &Context, download: &Download, variant_data: VariantData, target: &Path) -> Result<()> { +async fn download_ffmpeg( + ctx: &Context, + download: &Download, + variant_data: VariantData, + target: &Path, +) -> Result<()> { let (input_presets, output_presets) = FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?; diff --git a/crunchy-cli-core/src/cli/log.rs b/crunchy-cli-core/src/cli/log.rs index d1f0225..377685b 100644 --- a/crunchy-cli-core/src/cli/log.rs +++ b/crunchy-cli-core/src/cli/log.rs @@ -1,106 +1,17 @@ +use indicatif::{ProgressBar, ProgressStyle}; use log::{ set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError, }; use std::io::{stdout, Write}; -use std::sync::{mpsc, Mutex}; +use std::sync::Mutex; use std::thread; -use std::thread::JoinHandle; use std::time::Duration; -struct CliProgress { - handler: JoinHandle<()>, - sender: mpsc::SyncSender<(String, Level)>, -} - -impl CliProgress { - fn new(record: &Record) -> Self { - let (tx, rx) = mpsc::sync_channel(1); - - let init_message = format!("{}", record.args()); - let init_level = record.level(); - let handler = thread::spawn(move || { - #[cfg(not(windows))] - let ok = '✔'; - #[cfg(windows)] - // windows does not support all unicode characters by default in their consoles, so - // we're using this (square root?) symbol instead. microsoft. - let ok = '√'; - let states = ["-", "\\", "|", "/"]; - - let mut old_message = init_message.clone(); - let mut latest_info_message = init_message; - let mut old_level = init_level; - for i in 0.. { - let (msg, level) = match rx.try_recv() { - Ok(payload) => payload, - Err(e) => match e { - mpsc::TryRecvError::Empty => (old_message.clone(), old_level), - mpsc::TryRecvError::Disconnected => break, - }, - }; - - // clear last line - // prefix (2), space (1), state (1), space (1), message(n) - let _ = write!(stdout(), "\r {}", " ".repeat(old_message.len())); - - if old_level != level || old_message != msg { - if old_level <= Level::Warn { - let _ = writeln!(stdout(), "\r:: • {}", old_message); - } else if old_level == Level::Info && level <= Level::Warn { - let _ = writeln!(stdout(), "\r:: → {}", old_message); - } else if level == Level::Info { - latest_info_message = msg.clone(); - } - } - - let _ = write!( - stdout(), - "\r:: {} {}", - states[i / 2 % states.len()], - if level == Level::Info { - &msg - } else { - &latest_info_message - } - ); - let _ = stdout().flush(); - - old_message = msg; - old_level = level; - - thread::sleep(Duration::from_millis(100)); - } - - // clear last line - // prefix (2), space (1), state (1), space (1), message(n) - let _ = write!(stdout(), "\r {}", " ".repeat(old_message.len())); - let _ = writeln!(stdout(), "\r:: {} {}", ok, old_message); - let _ = stdout().flush(); - }); - - Self { - handler, - sender: tx, - } - } - - fn send(&self, record: &Record) { - let _ = self - .sender - .send((format!("{}", record.args()), record.level())); - } - - fn stop(self) { - drop(self.sender); - let _ = self.handler.join(); - } -} - #[allow(clippy::type_complexity)] pub struct CliLogger { all: bool, level: LevelFilter, - progress: Mutex>, + progress: Mutex>, } impl Log for CliLogger { @@ -127,7 +38,7 @@ impl Log for CliLogger { "progress_end" => self.progress(record, true), _ => { if self.progress.lock().unwrap().is_some() { - self.progress(record, false); + self.progress(record, false) } else if record.level() > Level::Warn { self.normal(record) } else { @@ -182,13 +93,34 @@ impl CliLogger { } fn progress(&self, record: &Record, stop: bool) { - let mut progress_option = self.progress.lock().unwrap(); - if stop && progress_option.is_some() { - progress_option.take().unwrap().stop() - } else if let Some(p) = &*progress_option { - p.send(record); + let mut progress = self.progress.lock().unwrap(); + + let msg = format!("{}", record.args()); + if stop && progress.is_some() { + if msg.is_empty() { + progress.take().unwrap().finish() + } else { + progress.take().unwrap().finish_with_message(msg) + } + } else if let Some(p) = &*progress { + p.println(format!(":: → {}", msg)) } else { - *progress_option = Some(CliProgress::new(record)) + #[cfg(not(windows))] + let finish_str = "✔"; + #[cfg(windows)] + // windows does not support all unicode characters by default in their consoles, so + // we're using this (square root?) symbol instead. microsoft. + let finish_str = "√"; + + let pb = ProgressBar::new_spinner(); + pb.set_style( + ProgressStyle::with_template(":: {spinner} {msg}") + .unwrap() + .tick_strings(&["-", "\\", "|", "/", finish_str]), + ); + pb.enable_steady_tick(Duration::from_millis(200)); + pb.set_message(msg); + *progress = Some(pb) } } } diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs index a64057a..6045ce4 100644 --- a/crunchy-cli-core/src/cli/utils.rs +++ b/crunchy-cli-core/src/cli/utils.rs @@ -1,13 +1,12 @@ use crate::utils::context::Context; use anyhow::{bail, Result}; use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment}; +use indicatif::{ProgressBar, ProgressFinish, ProgressStyle}; use log::{debug, LevelFilter}; use std::borrow::{Borrow, BorrowMut}; use std::collections::BTreeMap; -use std::io; use std::io::Write; use std::sync::{mpsc, Arc, Mutex}; -use std::time::Duration; use tokio::task::JoinSet; pub fn find_resolution( @@ -35,78 +34,25 @@ pub async fn download_segments( let client = Arc::new(ctx.crunchy.client()); let count = Arc::new(Mutex::new(0)); - let amount = Arc::new(Mutex::new(0)); - // only print progress when log level is info - let output_handler = if log::max_level() == LevelFilter::Info { - let output_count = count.clone(); - let output_amount = amount.clone(); - Some(tokio::spawn(async move { - let sleep_time_ms = 100; - let iter_per_sec = 1000f64 / sleep_time_ms as f64; + let progress = if log::max_level() == LevelFilter::Info { + let estimated_file_size = (variant_data.bandwidth / 8) + * segments + .iter() + .map(|s| s.length.unwrap_or_default().as_secs()) + .sum::(); - let mut bytes_start = 0f64; - let mut speed = 0f64; - let mut percentage = 0f64; - - while *output_count.lock().unwrap() < total_segments || percentage < 100f64 { - let tmp_amount = *output_amount.lock().unwrap() as f64; - - let tmp_speed = (tmp_amount - bytes_start) / 1024f64 / 1024f64; - if *output_count.lock().unwrap() < 3 { - speed = tmp_speed; - } else { - let (old_speed_ratio, new_speed_ratio) = if iter_per_sec <= 1f64 { - (0f64, 1f64) - } else { - (1f64 - (1f64 / iter_per_sec), (1f64 / iter_per_sec)) - }; - - // calculate the average download speed "smoother" - speed = (speed * old_speed_ratio) + (tmp_speed * new_speed_ratio); - } - - percentage = - (*output_count.lock().unwrap() as f64 / total_segments as f64) * 100f64; - - let size = terminal_size::terminal_size() - .unwrap_or((terminal_size::Width(60), terminal_size::Height(0))) - .0 - .0 as usize; - - // there is a offset of 1 "length" (idk how to describe it), so removing 1 from - // `progress_available` would fill the terminal width completely. on multiple - // systems there is a bug that printing until the end of the line causes a newline - // even though technically there shouldn't be one. on my tests, this only happens on - // windows and mac machines and (at the addressed environments) only with release - // builds. so maybe an unwanted optimization? - let progress_available = size - - if let Some(msg) = &message { - 35 + msg.len() - } else { - 34 - }; - let progress_done_count = - (progress_available as f64 * (percentage / 100f64)).ceil() as usize; - let progress_to_do_count = progress_available - progress_done_count; - - let _ = write!( - io::stdout(), - "\r:: {}{:>5.1} MiB {:>5.2} MiB/s [{}{}] {:>3}%", - message.clone().map_or("".to_string(), |msg| msg + " "), - tmp_amount / 1024f64 / 1024f64, - speed * iter_per_sec, - "#".repeat(progress_done_count), - "-".repeat(progress_to_do_count), - percentage as usize - ); - - bytes_start = tmp_amount; - - tokio::time::sleep(Duration::from_millis(sleep_time_ms)).await; - } - println!() - })) + let progress = ProgressBar::new(estimated_file_size) + .with_style( + ProgressStyle::with_template( + ":: {msg}{bytes:>10} {bytes_per_sec:>12} [{wide_bar}] {percent:>3}%", + ) + .unwrap() + .progress_chars("##-"), + ) + .with_message(message.map(|m| m + " ").unwrap_or_default()) + .with_finish(ProgressFinish::Abandon); + Some(progress) } else { None }; @@ -116,7 +62,7 @@ pub async fn download_segments( for _ in 0..cpus { segs.push(vec![]) } - for (i, segment) in segments.into_iter().enumerate() { + for (i, segment) in segments.clone().into_iter().enumerate() { segs[i - ((i / cpus) * cpus)].push(segment); } @@ -127,15 +73,12 @@ pub async fn download_segments( let thread_client = client.clone(); let thread_sender = sender.clone(); let thread_segments = segs.remove(0); - let thread_amount = amount.clone(); let thread_count = count.clone(); join_set.spawn(async move { for (i, segment) in thread_segments.into_iter().enumerate() { let response = thread_client.get(&segment.url).send().await?; let mut buf = response.bytes().await?.to_vec(); - *thread_amount.lock().unwrap() += buf.len(); - buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec(); debug!( "Downloaded and decrypted segment {} ({})", @@ -155,13 +98,28 @@ pub async fn download_segments( let mut buf: BTreeMap> = BTreeMap::new(); loop { // is always `Some` because `sender` does not get dropped when all threads are finished - let data = receiver.recv().unwrap(); + let (pos, bytes) = receiver.recv().unwrap(); - if data_pos == data.0 { - writer.write_all(data.1.borrow())?; + if let Some(p) = &progress { + let progress_len = p.length().unwrap(); + let estimated_segment_len = (variant_data.bandwidth / 8) + * segments + .get(pos) + .unwrap() + .length + .unwrap_or_default() + .as_secs(); + let bytes_len = bytes.len() as u64; + + p.set_length(progress_len - estimated_segment_len + bytes_len); + p.inc(bytes_len) + } + + if data_pos == pos { + writer.write_all(bytes.borrow())?; data_pos += 1; } else { - buf.insert(data.0, data.1); + buf.insert(pos, bytes); } while let Some(b) = buf.remove(&data_pos) { writer.write_all(b.borrow())?; @@ -176,9 +134,6 @@ pub async fn download_segments( while let Some(joined) = join_set.join_next().await { joined?? } - if let Some(handler) = output_handler { - handler.await? - } Ok(()) } @@ -200,7 +155,7 @@ impl ToString for FFmpegPreset { &FFmpegPreset::H265 => "h265", &FFmpegPreset::H264 => "h264", } - .to_string() + .to_string() } } @@ -233,7 +188,9 @@ impl FFmpegPreset { }) } - pub(crate) fn ffmpeg_presets(mut presets: Vec) -> Result<(Vec, Vec)> { + pub(crate) fn ffmpeg_presets( + mut presets: Vec, + ) -> Result<(Vec, Vec)> { fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool { if let Some(i) = presets.iter().position(|p| p == &preset) { presets.remove(i); diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs index d669b64..00699e4 100644 --- a/crunchy-cli-core/src/lib.rs +++ b/crunchy-cli-core/src/lib.rs @@ -6,7 +6,7 @@ use anyhow::bail; use anyhow::Result; use clap::{Parser, Subcommand}; use crunchyroll_rs::{Crunchyroll, Locale}; -use log::{debug, error, info, LevelFilter}; +use log::{debug, error, LevelFilter}; use std::{env, fs}; mod cli; @@ -196,7 +196,7 @@ async fn crunchyroll_session(cli: &Cli) -> Result { + cli.login_method.etp_rt.is_some() as u8 + cli.login_method.anonymous as u8; - let _progress_handler = progress!("Logging in"); + let progress_handler = progress!("Logging in"); if login_methods_count == 0 { if let Some(login_file_path) = cli::login::login_file_path() { if login_file_path.exists() { @@ -232,7 +232,7 @@ async fn crunchyroll_session(cli: &Cli) -> Result { bail!("should never happen") }; - info!("Logged in"); + progress_handler.stop("Logged in"); Ok(crunchy) } diff --git a/crunchy-cli-core/src/utils/log.rs b/crunchy-cli-core/src/utils/log.rs index b9fa939..24fed5d 100644 --- a/crunchy-cli-core/src/utils/log.rs +++ b/crunchy-cli-core/src/utils/log.rs @@ -1,10 +1,21 @@ use log::info; -pub struct ProgressHandler; +pub struct ProgressHandler { + pub(crate) stopped: bool, +} impl Drop for ProgressHandler { fn drop(&mut self) { - info!(target: "progress_end", "") + if !self.stopped { + info!(target: "progress_end", "") + } + } +} + +impl ProgressHandler { + pub(crate) fn stop>(mut self, msg: S) { + self.stopped = true; + info!(target: "progress_end", "{}", msg.as_ref()) } } @@ -12,7 +23,7 @@ macro_rules! progress { ($($arg:tt)+) => { { log::info!(target: "progress", $($arg)+); - $crate::utils::log::ProgressHandler{} + $crate::utils::log::ProgressHandler{stopped: false} } } }