From e694046b07fbcabf40714e62d1ac7a98f511fcdd Mon Sep 17 00:00:00 2001 From: bytedream Date: Wed, 3 Apr 2024 15:48:15 +0200 Subject: [PATCH] Move to new, DRM-free, endpoint --- Cargo.lock | 404 ++++++++++------------- crunchy-cli-core/Cargo.toml | 6 +- crunchy-cli-core/src/archive/command.rs | 2 +- crunchy-cli-core/src/download/command.rs | 2 +- crunchy-cli-core/src/search/format.rs | 36 +- crunchy-cli-core/src/utils/download.rs | 57 ++-- crunchy-cli-core/src/utils/format.rs | 31 +- crunchy-cli-core/src/utils/video.rs | 38 +-- 8 files changed, 245 insertions(+), 331 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 113b430..b7617b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,17 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -156,13 +145,19 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64-serde" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba368df5de76a5bea49aaf0cf1b39ccfbbef176924d1ba5db3e4135216cbe3c7" dependencies = [ - "base64", + "base64 0.21.7", "serde", ] @@ -178,15 +173,6 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "bumpalo" version = "3.15.4" @@ -199,15 +185,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.0.90" @@ -228,9 +205,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -241,16 +218,6 @@ dependencies = [ "windows-targets 0.52.4", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "4.5.2" @@ -373,15 +340,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - [[package]] name = "crunchy-cli" version = "3.3.1" @@ -432,20 +390,17 @@ dependencies = [ [[package]] name = "crunchyroll-rs" -version = "0.8.6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f99fcd7627d214fd57cd1d030e8c859a773e19aa29fb0d15017aa84efaba353" +checksum = "05fcd99a09d001333ab482412473aaa03c84f980d451845b4c43d58986b6eb64" dependencies = [ - "aes", "async-trait", - "cbc", "chrono", "crunchyroll-rs-internal", "dash-mpd", "futures-util", "jsonwebtoken", "lazy_static", - "m3u8-rs", "regex", "reqwest", "rustls", @@ -455,30 +410,20 @@ dependencies = [ "smart-default", "tokio", "tower-service", - "webpki-roots 0.26.1", + "webpki-roots", ] [[package]] name = "crunchyroll-rs-internal" -version = "0.8.6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dd269b2df82ebbec9e8164e9950c6ad14a01cfcbb85eceeb3f3ef26c7da90c" +checksum = "d406a27eca9ceab379b601101cd96b0f7bfff34e93487ca58d54118a8b4fbf91" dependencies = [ "darling", "quote", "syn", ] -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "ctrlc" version = "3.4.4" @@ -526,11 +471,11 @@ dependencies = [ [[package]] name = "dash-mpd" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c18f28b58beade78e0f61a846a63a122cb92c5f5ed6bad29d7ad13287c7526" +checksum = "6cafa2c33eff2857e1a14c38aa9a432aa565a01e77804a541fce7aec3affb8f8" dependencies = [ - "base64", + "base64 0.22.0", "base64-serde", "chrono", "fs-err", @@ -614,15 +559,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -761,16 +697,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.12" @@ -790,25 +716,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.5", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -841,9 +748,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -852,12 +759,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -867,61 +786,76 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "hyper" -version = "0.14.28" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", "http", "hyper", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", ] [[package]] name = "hyper-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", + "http-body-util", "hyper", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1008,16 +942,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "instant" version = "0.1.12" @@ -1059,11 +983,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.2.0" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ - "base64", + "base64 0.21.7", "js-sys", "ring", "serde", @@ -1105,16 +1029,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "m3u8-rs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03cd3335fb5f2447755d45cda9c70f76013626a9db44374973791b0926a86c3" -dependencies = [ - "chrono", - "nom", -] - [[package]] name = "memchr" version = "2.7.1" @@ -1127,6 +1041,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1303,6 +1227,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1399,9 +1343,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1428,38 +1372,39 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.25" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eea5a9eb898d3783f17c6407670e3592fd174cb81a10e51d4c37f49450b9946" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "cookie", "cookie_store", - "encoding_rs", "futures-core", "futures-util", - "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-rustls", "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", "rustls", "rustls-pemfile 1.0.4", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -1471,7 +1416,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.25.4", + "webpki-roots", "winreg", ] @@ -1517,14 +1462,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" dependencies = [ "log", "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] @@ -1546,7 +1493,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] @@ -1555,7 +1502,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" dependencies = [ - "base64", + "base64 0.21.7", "rustls-pki-types", ] @@ -1567,11 +1514,12 @@ checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] @@ -1590,16 +1538,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "security-framework" version = "2.9.2" @@ -1687,11 +1625,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ - "base64", + "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", @@ -1705,9 +1643,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" +checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" dependencies = [ "darling", "proc-macro2", @@ -1736,6 +1674,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "smart-default" version = "0.7.1" @@ -1775,6 +1719,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "2.0.52" @@ -1801,27 +1751,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" -dependencies = [ - "bitflags 2.4.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tempfile" version = "3.10.1" @@ -1836,18 +1765,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -1902,9 +1831,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -1940,11 +1869,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ "rustls", + "rustls-pki-types", "tokio", ] @@ -1974,6 +1904,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1986,6 +1938,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2018,10 +1971,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "typenum" -version = "1.17.0" +name = "unicase" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] [[package]] name = "unicode-bidi" @@ -2189,12 +2145,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.1" @@ -2387,3 +2337,9 @@ dependencies = [ "linux-raw-sys", "rustix", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml index 0242606..7617c58 100644 --- a/crunchy-cli-core/Cargo.toml +++ b/crunchy-cli-core/Cargo.toml @@ -16,20 +16,20 @@ anyhow = "1.0" async-speed-limit = "0.4" clap = { version = "4.5", features = ["derive", "string"] } chrono = "0.4" -crunchyroll-rs = { version = "0.8.6", features = ["dash-stream", "experimental-stabilizations", "tower"] } +crunchyroll-rs = { version = "0.10.0", features = ["experimental-stabilizations", "tower"] } ctrlc = "3.4" dialoguer = { version = "0.11", default-features = false } dirs = "5.0" derive_setters = "0.1" futures-util = { version = "0.3", features = ["io"] } fs2 = "0.4" -http = "0.2" +http = "1.1" indicatif = "0.17" lazy_static = "1.4" log = { version = "0.4", features = ["std"] } num_cpus = "1.16" regex = "1.10" -reqwest = { version = "0.11", default-features = false, features = ["socks", "stream"] } +reqwest = { version = "0.12", default-features = false, features = ["socks", "stream"] } serde = "1.0" serde_json = "1.0" serde_plain = "1.0" diff --git a/crunchy-cli-core/src/archive/command.rs b/crunchy-cli-core/src/archive/command.rs index f7bea0e..0dc0b86 100644 --- a/crunchy-cli-core/src/archive/command.rs +++ b/crunchy-cli-core/src/archive/command.rs @@ -487,7 +487,7 @@ async fn get_format( single_format.audio == Locale::ja_JP || stream.subtitles.len() > 1, ) }); - let cc = stream.closed_captions.get(s).cloned().map(|l| (l, false)); + let cc = stream.captions.get(s).cloned().map(|l| (l, false)); subtitles .into_iter() diff --git a/crunchy-cli-core/src/download/command.rs b/crunchy-cli-core/src/download/command.rs index 843f5cd..47b29c9 100644 --- a/crunchy-cli-core/src/download/command.rs +++ b/crunchy-cli-core/src/download/command.rs @@ -389,7 +389,7 @@ async fn get_format( .get(subtitle_locale) .cloned() // use closed captions as fallback if no actual subtitles are found - .or_else(|| stream.closed_captions.get(subtitle_locale).cloned()) + .or_else(|| stream.captions.get(subtitle_locale).cloned()) } else { None }; diff --git a/crunchy-cli-core/src/search/format.rs b/crunchy-cli-core/src/search/format.rs index 156bd95..10eefd8 100644 --- a/crunchy-cli-core/src/search/format.rs +++ b/crunchy-cli-core/src/search/format.rs @@ -163,37 +163,15 @@ impl From<&Concert> for FormatConcert { struct FormatStream { pub locale: Locale, pub dash_url: String, - pub drm_dash_url: String, - pub hls_url: String, - pub drm_hls_url: String, + pub is_drm: bool, } impl From<&Stream> for FormatStream { fn from(value: &Stream) -> Self { - let (dash_url, drm_dash_url, hls_url, drm_hls_url) = - value.variants.get(&Locale::Custom("".to_string())).map_or( - ( - "".to_string(), - "".to_string(), - "".to_string(), - "".to_string(), - ), - |v| { - ( - v.adaptive_dash.clone().unwrap_or_default().url, - v.drm_adaptive_dash.clone().unwrap_or_default().url, - v.adaptive_hls.clone().unwrap_or_default().url, - v.drm_adaptive_hls.clone().unwrap_or_default().url, - ) - }, - ); - Self { locale: value.audio_locale.clone(), - dash_url, - drm_dash_url, - hls_url, - drm_hls_url, + dash_url: value.url.clone(), + is_drm: value.session.uses_stream_limits, } } } @@ -441,7 +419,7 @@ impl Format { if !stream_empty { for (_, episodes) in tree.iter_mut() { for (episode, streams) in episodes { - streams.push(episode.stream().await?) + streams.push(episode.stream_maybe_without_drm().await?) } } } else { @@ -510,7 +488,7 @@ impl Format { } if !stream_empty { for (movie, streams) in tree.iter_mut() { - streams.push(movie.stream().await?) + streams.push(movie.stream_maybe_without_drm().await?) } } else { for (_, streams) in tree.iter_mut() { @@ -548,7 +526,7 @@ impl Format { let stream_empty = self.check_pattern_count_empty(Scope::Stream); let music_video = must_match_if_true!(!music_video_empty => media_collection|MediaCollection::MusicVideo(music_video) => music_video.clone()).unwrap_or_default(); - let stream = must_match_if_true!(!stream_empty => media_collection|MediaCollection::MusicVideo(music_video) => music_video.stream().await?).unwrap_or_default(); + let stream = must_match_if_true!(!stream_empty => media_collection|MediaCollection::MusicVideo(music_video) => music_video.stream_maybe_without_drm().await?).unwrap_or_default(); let music_video_map = self.serializable_to_json_map(FormatMusicVideo::from(&music_video)); let stream_map = self.serializable_to_json_map(FormatStream::from(&stream)); @@ -570,7 +548,7 @@ impl Format { let stream_empty = self.check_pattern_count_empty(Scope::Stream); let concert = must_match_if_true!(!concert_empty => media_collection|MediaCollection::Concert(concert) => concert.clone()).unwrap_or_default(); - let stream = must_match_if_true!(!stream_empty => media_collection|MediaCollection::Concert(concert) => concert.stream().await?).unwrap_or_default(); + let stream = must_match_if_true!(!stream_empty => media_collection|MediaCollection::Concert(concert) => concert.stream_maybe_without_drm().await?).unwrap_or_default(); let concert_map = self.serializable_to_json_map(FormatConcert::from(&concert)); let stream_map = self.serializable_to_json_map(FormatStream::from(&stream)); diff --git a/crunchy-cli-core/src/utils/download.rs b/crunchy-cli-core/src/utils/download.rs index 736f9e6..8a1fe66 100644 --- a/crunchy-cli-core/src/utils/download.rs +++ b/crunchy-cli-core/src/utils/download.rs @@ -4,7 +4,7 @@ use crate::utils::os::{cache_dir, is_special_file, temp_directory, temp_named_pi use crate::utils::rate_limit::RateLimiterService; use anyhow::{bail, Result}; use chrono::NaiveTime; -use crunchyroll_rs::media::{SkipEvents, SkipEventsEvent, Subtitle, VariantData, VariantSegment}; +use crunchyroll_rs::media::{SkipEvents, SkipEventsEvent, StreamData, StreamSegment, Subtitle}; use crunchyroll_rs::Locale; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressFinish, ProgressStyle}; use log::{debug, warn, LevelFilter}; @@ -117,8 +117,8 @@ struct FFmpegMeta { } pub struct DownloadFormat { - pub video: (VariantData, Locale), - pub audios: Vec<(VariantData, Locale)>, + pub video: (StreamData, Locale), + pub audios: Vec<(StreamData, Locale)>, pub subtitles: Vec<(Subtitle, bool)>, pub metadata: DownloadFormatMetadata, } @@ -671,20 +671,17 @@ impl Downloader { &self, dst: &Path, ) -> Result<(Option<(PathBuf, u64)>, Option<(PathBuf, u64)>)> { - let mut all_variant_data = vec![]; + let mut all_stream_data = vec![]; for format in &self.formats { - all_variant_data.push(&format.video.0); - all_variant_data.extend(format.audios.iter().map(|(a, _)| a)) + all_stream_data.push(&format.video.0); + all_stream_data.extend(format.audios.iter().map(|(a, _)| a)) } let mut estimated_required_space: u64 = 0; - for variant_data in all_variant_data { - // nearly no overhead should be generated with this call(s) as we're using dash as - // stream provider and generating the dash segments does not need any fetching of - // additional (http) resources as hls segments would - let segments = variant_data.segments().await?; + for stream_data in all_stream_data { + let segments = stream_data.segments(); // sum the length of all streams up - estimated_required_space += estimate_variant_file_size(variant_data, &segments); + estimated_required_space += estimate_variant_file_size(stream_data, &segments); } let tmp_stat = fs2::statvfs(temp_directory()).unwrap(); @@ -730,29 +727,21 @@ impl Downloader { Ok((tmp_required, dst_required)) } - async fn download_video( - &self, - variant_data: &VariantData, - message: String, - ) -> Result { + async fn download_video(&self, stream_data: &StreamData, message: String) -> Result { let tempfile = tempfile(".mp4")?; let (mut file, path) = tempfile.into_parts(); - self.download_segments(&mut file, message, variant_data) + self.download_segments(&mut file, message, stream_data) .await?; Ok(path) } - async fn download_audio( - &self, - variant_data: &VariantData, - message: String, - ) -> Result { + async fn download_audio(&self, stream_data: &StreamData, message: String) -> Result { let tempfile = tempfile(".m4a")?; let (mut file, path) = tempfile.into_parts(); - self.download_segments(&mut file, message, variant_data) + self.download_segments(&mut file, message, stream_data) .await?; Ok(path) @@ -806,15 +795,15 @@ impl Downloader { &self, writer: &mut impl Write, message: String, - variant_data: &VariantData, + stream_data: &StreamData, ) -> Result<()> { - let segments = variant_data.segments().await?; + let segments = stream_data.segments(); let total_segments = segments.len(); let count = Arc::new(Mutex::new(0)); let progress = if log::max_level() == LevelFilter::Info { - let estimated_file_size = estimate_variant_file_size(variant_data, &segments); + let estimated_file_size = estimate_variant_file_size(stream_data, &segments); let progress = ProgressBar::new(estimated_file_size) .with_style( @@ -832,7 +821,7 @@ impl Downloader { }; let cpus = self.download_threads; - let mut segs: Vec> = Vec::with_capacity(cpus); + let mut segs: Vec> = Vec::with_capacity(cpus); for _ in 0..cpus { segs.push(vec![]) } @@ -858,7 +847,7 @@ impl Downloader { let download = || async move { for (i, segment) in thread_segments.into_iter().enumerate() { let mut retry_count = 0; - let mut buf = loop { + let buf = loop { let request = thread_client .get(&segment.url) .timeout(Duration::from_secs(60)); @@ -884,11 +873,9 @@ impl Downloader { retry_count += 1; }; - buf = VariantSegment::decrypt(&mut buf, segment.key)?.to_vec(); - let mut c = thread_count.lock().await; debug!( - "Downloaded and decrypted segment [{}/{} {:.2}%] {}", + "Downloaded segment [{}/{} {:.2}%] {}", num + (i * cpus) + 1, total_segments, ((*c + 1) as f64 / total_segments as f64) * 100f64, @@ -928,7 +915,7 @@ impl Downloader { if let Some(p) = &progress { let progress_len = p.length().unwrap(); - let estimated_segment_len = (variant_data.bandwidth / 8) + let estimated_segment_len = (stream_data.bandwidth / 8) * segments.get(pos as usize).unwrap().length.as_secs(); let bytes_len = bytes.len() as u64; @@ -977,8 +964,8 @@ impl Downloader { } } -fn estimate_variant_file_size(variant_data: &VariantData, segments: &[VariantSegment]) -> u64 { - (variant_data.bandwidth / 8) * segments.iter().map(|s| s.length.as_secs()).sum::() +fn estimate_variant_file_size(stream_data: &StreamData, segments: &[StreamSegment]) -> u64 { + (stream_data.bandwidth / 8) * segments.iter().map(|s| s.length.as_secs()).sum::() } /// Get the length and fps of a video. diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs index 7146a55..df79d64 100644 --- a/crunchy-cli-core/src/utils/format.rs +++ b/crunchy-cli-core/src/utils/format.rs @@ -2,9 +2,9 @@ use crate::utils::filter::real_dedup_vec; use crate::utils::locale::LanguageTagging; use crate::utils::log::tab_info; use crate::utils::os::{is_special_file, sanitize}; -use anyhow::Result; +use anyhow::{bail, Result}; use chrono::{Datelike, Duration}; -use crunchyroll_rs::media::{Resolution, SkipEvents, Stream, Subtitle, VariantData}; +use crunchyroll_rs::media::{Resolution, SkipEvents, Stream, StreamData, Subtitle}; use crunchyroll_rs::{Concert, Episode, Locale, MediaCollection, Movie, MusicVideo}; use log::{debug, info}; use std::cmp::Ordering; @@ -167,12 +167,17 @@ impl SingleFormat { pub async fn stream(&self) -> Result { let stream = match &self.source { - MediaCollection::Episode(e) => e.stream().await?, - MediaCollection::Movie(m) => m.stream().await?, - MediaCollection::MusicVideo(mv) => mv.stream().await?, - MediaCollection::Concert(c) => c.stream().await?, + MediaCollection::Episode(e) => e.stream_maybe_without_drm().await?, + MediaCollection::Movie(m) => m.stream_maybe_without_drm().await?, + MediaCollection::MusicVideo(mv) => mv.stream_maybe_without_drm().await?, + MediaCollection::Concert(c) => c.stream_maybe_without_drm().await?, _ => unreachable!(), }; + + if stream.session.uses_stream_limits { + bail!("Found a stream which probably uses DRM. DRM downloads aren't supported") + } + Ok(stream) } @@ -331,9 +336,7 @@ impl Iterator for SingleFormatCollectionIterator { type Item = Vec; fn next(&mut self) -> Option { - let Some((_, episodes)) = self.0 .0.iter_mut().next() else { - return None; - }; + let (_, episodes) = self.0 .0.iter_mut().next()?; let value = episodes.pop_first().unwrap().1; if episodes.is_empty() { @@ -377,7 +380,7 @@ pub struct Format { impl Format { #[allow(clippy::type_complexity)] pub fn from_single_formats( - mut single_formats: Vec<(SingleFormat, VariantData, Vec<(Subtitle, bool)>)>, + mut single_formats: Vec<(SingleFormat, StreamData, Vec<(Subtitle, bool)>)>, ) -> Self { let locales: Vec<(Locale, Vec)> = single_formats .iter() @@ -397,10 +400,10 @@ impl Format { title: first_format.title, description: first_format.description, locales, - resolution: first_stream.resolution.clone(), - width: first_stream.resolution.width, - height: first_stream.resolution.height, - fps: first_stream.fps, + resolution: first_stream.resolution().unwrap(), + width: first_stream.resolution().unwrap().width, + height: first_stream.resolution().unwrap().height, + fps: first_stream.fps().unwrap(), release_year: first_format.release_year, release_month: first_format.release_month, release_day: first_format.release_day, diff --git a/crunchy-cli-core/src/utils/video.rs b/crunchy-cli-core/src/utils/video.rs index 0ae4ba4..7f7d73e 100644 --- a/crunchy-cli-core/src/utils/video.rs +++ b/crunchy-cli-core/src/utils/video.rs @@ -1,17 +1,17 @@ use anyhow::{bail, Result}; -use crunchyroll_rs::media::{Resolution, Stream, VariantData}; +use crunchyroll_rs::media::{Resolution, Stream, StreamData}; use crunchyroll_rs::Locale; pub async fn variant_data_from_stream( stream: &Stream, resolution: &Resolution, subtitle: Option, -) -> Result> { +) -> Result> { // sometimes Crunchyroll marks episodes without real subtitles that they have subtitles and // reports that only hardsub episode are existing. the following lines are trying to prevent // potential errors which might get caused by this incorrect reporting // (https://github.com/crunchy-labs/crunchy-cli/issues/231) - let mut hardsub_locales = stream.streaming_hardsub_locales(); + let mut hardsub_locales: Vec = stream.hard_subs.keys().cloned().collect(); let (hardsub_locale, mut contains_hardsub) = if !hardsub_locales .contains(&Locale::Custom("".to_string())) && !hardsub_locales.contains(&Locale::Custom(":".to_string())) @@ -29,39 +29,29 @@ pub async fn variant_data_from_stream( (subtitle, hardsubs_requested) }; - let mut streaming_data = match stream.dash_streaming_data(hardsub_locale).await { + let (mut videos, mut audios) = match stream.stream_data(hardsub_locale).await { Ok(data) => data, Err(e) => { // the error variant is only `crunchyroll_rs::error::Error::Input` when the requested // hardsub is not available if let crunchyroll_rs::error::Error::Input { .. } = e { contains_hardsub = false; - stream.dash_streaming_data(None).await? + stream.stream_data(None).await? } else { bail!(e) } } - }; - streaming_data - .0 - .sort_by(|a, b| a.bandwidth.cmp(&b.bandwidth).reverse()); - streaming_data - .1 - .sort_by(|a, b| a.bandwidth.cmp(&b.bandwidth).reverse()); + } + .unwrap(); + videos.sort_by(|a, b| a.bandwidth.cmp(&b.bandwidth).reverse()); + audios.sort_by(|a, b| a.bandwidth.cmp(&b.bandwidth).reverse()); let video_variant = match resolution.height { - u64::MAX => Some(streaming_data.0.into_iter().next().unwrap()), - u64::MIN => Some(streaming_data.0.into_iter().last().unwrap()), - _ => streaming_data - .0 + u64::MAX => Some(videos.into_iter().next().unwrap()), + u64::MIN => Some(videos.into_iter().last().unwrap()), + _ => videos .into_iter() - .find(|v| resolution.height == v.resolution.height), + .find(|v| resolution.height == v.resolution().unwrap().height), }; - Ok(video_variant.map(|v| { - ( - v, - streaming_data.1.first().unwrap().clone(), - contains_hardsub, - ) - })) + Ok(video_variant.map(|v| (v, audios.first().unwrap().clone(), contains_hardsub))) }