diff --git a/Cargo.lock b/Cargo.lock index f2657d2..3c90212 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,47 +28,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -98,9 +99,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -149,9 +150,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.92" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" @@ -188,9 +189,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "console" @@ -257,9 +258,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -267,9 +268,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fnv" @@ -389,9 +390,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" @@ -535,6 +536,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itoa" version = "1.0.11" @@ -558,9 +565,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "linux-raw-sys" @@ -570,9 +577,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -721,9 +728,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -731,15 +738,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -774,9 +781,9 @@ checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -792,11 +799,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -872,16 +879,37 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.23" +name = "rpassword" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -901,9 +929,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" @@ -922,11 +950,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -935,9 +963,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -945,18 +973,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", @@ -965,9 +993,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -988,9 +1016,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -1012,9 +1040,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1028,9 +1056,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.58" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", @@ -1142,16 +1170,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -1165,7 +1192,7 @@ dependencies = [ [[package]] name = "tootube" -version = "0.5.5" +version = "0.6.0" dependencies = [ "async-stream", "clap", @@ -1174,6 +1201,7 @@ dependencies = [ "indicatif", "log", "reqwest", + "rpassword", "serde", "tokio", "toml", @@ -1242,9 +1270,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "url" @@ -1379,37 +1407,15 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.48.0" @@ -1425,7 +1431,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1445,17 +1451,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1466,9 +1473,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1478,9 +1485,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1490,9 +1497,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1502,9 +1515,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1514,9 +1527,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1526,9 +1539,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1538,9 +1551,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" diff --git a/Cargo.toml b/Cargo.toml index 4bab03f..c8f3b92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "tootube" authors = ["VC "] -version = "0.5.5" +version = "0.6.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rpassword = "^7.3" reqwest = { version = "^0.11", features = ["json", "stream", "multipart"] } tokio = { version = "^1", features = ["full"] } clap = "^4" diff --git a/README.md b/README.md index 6cb3ced..7121fe1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ So consider this a work in progress that will slowly get better with time. # What does it do exactly? * it retrieves the latest PeerTube video download URL from an instance +* if you register the app into your PeerTube instance (optional), you can retrieve the latest video source instead of the highest quality encoded video * it creates a resumable upload into the target YouTube account * it downloads/uploads the latest PeerTube video to YouTube without using a cache (stream-to-stream) @@ -46,6 +47,15 @@ Create your `tootube.toml` config file: ```toml [peertube] base_url="https://p.nintendojo.fr" +# optional +# allows you to delete the original video source file once it’s uploaded to YouTube +delete_video_source_after_transfer=true # this option is only available if you have Administrator privileges +# optional +# everything below is given by the register command with --peertube option +[peertube.oauth2] +client_id="" +client_secret=" +tootube register --youtube --config ``` You’ll be then prompted with all the necessary information to register `tootube`. You’ll end with a `refresh_token` that you can now paste inside your tootube configuration. + +If you wish to register `tootube` on PeerTube, you can do so by using: + +```bash +tootube register --peertube --config +``` + +It will require your username/password (beware that 2FA is not supported for this feature as of now) and generate a first `refresh_token` that you will put inside the aformentioned file: + +```bash +echo -n '' > /var/lib/tootube/refresh_token +``` diff --git a/src/config.rs b/src/config.rs index 3aa1454..fb1dc68 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,6 +13,26 @@ pub struct Config { #[derive(Debug, Deserialize)] pub struct PeertubeConfig { pub base_url: String, + #[serde(default)] + pub delete_video_source_after_transfer: bool, + pub oauth2: Option, +} + +impl Default for PeertubeConfig { + fn default() -> Self { + PeertubeConfig { + base_url: "".to_string(), + delete_video_source_after_transfer: false, + oauth2: None, + } + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct PeertubeConfigOauth2 { + pub client_id: String, + pub client_secret: String, + pub refresh_token: String, } #[derive(Debug, Deserialize)] diff --git a/src/lib.rs b/src/lib.rs index 1574e8d..5abf2c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,11 @@ pub use config::parse_toml; use config::Config; mod peertube; -use peertube::get_latest_video; +pub use peertube::register as register_peertube; +use peertube::{delete_original_video_source, get_latest_video, get_original_video_source}; mod youtube; -pub use youtube::register; +pub use youtube::register as register_youtube; use youtube::{add_video_to_playlists, create_resumable_upload, now_kiss}; #[tokio::main] @@ -22,13 +23,29 @@ pub async fn run(config: Config, pl: Vec) { panic!("Cannot retrieve the latest video, something must have gone terribly wrong: {e}") }); - let dl_url = latest_vid.streaming_playlists.as_ref().unwrap()[0] + // We have a refresh_token, try to use it + let source_url = match &config.peertube.oauth2 { + Some(_) => get_original_video_source(&latest_vid.uuid, &config.peertube) + .await + .ok(), + None => None, + }; + + // Whatever happens, collect the highest quality possible + let high_quality_url = latest_vid.streaming_playlists.as_ref().unwrap()[0] .files .iter() .max() .unwrap() .file_download_url .clone(); + + // dl_url corresponds to source url if available, best quality if not + let dl_url = match source_url { + Some(s) => s, + None => high_quality_url, + }; + debug!("PT download URL: {}", &dl_url); let resumable_upload_url = create_resumable_upload(&config.youtube, &latest_vid) @@ -51,4 +68,13 @@ pub async fn run(config: Config, pl: Vec) { .await .unwrap_or_else(|e| panic!("Cannot add video to playlist(s): {e}")); } + + // delete the source video if requested (it won’t be used anymore) + if config.peertube.delete_video_source_after_transfer { + delete_original_video_source(&latest_vid.uuid, &config.peertube) + .await + .unwrap_or_else(|e| panic!("Cannot delete source video: {e}")); + + debug!("Original Video {} has been deleted", &latest_vid.uuid); + } } diff --git a/src/main.rs b/src/main.rs index 7f767ec..de93fb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ fn main() { .arg( Arg::new("config") .short('c') + .global(true) .long("config") .value_name("CONFIG_FILE") .help("TOML config file for tootube") @@ -29,32 +30,45 @@ fn main() { .arg( Arg::new("vice") .long("vice") - .alias("chybrare") - .alias("coquinou") + .aliases(["chybrare", "coquinou"]) .action(clap::ArgAction::SetTrue) .display_order(3), ) .subcommand( Command::new("register") .version(env!("CARGO_PKG_VERSION")) - .about("Command to register to YouTube OAuth2.0") + .about("Command to register to YouTube or PeerTube OAuth2.0") .arg( - Arg::new("config") - .short('c') - .long("config") - .value_name("CONFIG_FILE") - .help("TOML config file for tootube") - .num_args(1) - .default_value(DEFAULT_CONFIG_PATH) - .display_order(1), + Arg::new("youtube") + .long("youtube") + .short('y') + .required(true) + .conflicts_with("peertube") + .action(clap::ArgAction::SetTrue), + ) + .arg( + Arg::new("peertube") + .long("peertube") + .short('p') + .required(true) + .action(clap::ArgAction::SetTrue), ), ) .get_matches(); if let Some(("register", sub_m)) = matches.subcommand() { let config = parse_toml(sub_m.get_one::("config").unwrap()); - register(&config.youtube) - .unwrap_or_else(|e| panic!("Cannot register to YouTube API: {}", e)); + + if sub_m.get_flag("youtube") { + register_youtube(&config.youtube) + .unwrap_or_else(|e| panic!("Cannot register to YouTube API: {}", e)); + } + + if sub_m.get_flag("peertube") { + register_peertube(&config.peertube) + .unwrap_or_else(|e| panic!("Cannot register to PeerTube API: {}", e)); + } + return; } diff --git a/src/peertube.rs b/src/peertube.rs index 8d11700..858dba9 100644 --- a/src/peertube.rs +++ b/src/peertube.rs @@ -1,5 +1,10 @@ -use serde::Deserialize; -use std::{boxed::Box, cmp::Ordering, error::Error}; +use crate::{config::PeertubeConfig, error::TootubeError}; +use log::debug; +use reqwest::Client; +use rpassword::prompt_password; +use serde::{Deserialize, Serialize}; +use std::{boxed::Box, cmp::Ordering, error::Error, io::stdin}; +use tokio::fs::{read_to_string, write}; #[derive(Debug, Deserialize)] pub struct PeerTubeVideos { @@ -22,6 +27,44 @@ pub struct PeerTubeVideoStreamingPlaylists { pub files: Vec, } +#[derive(Debug, Deserialize)] +struct PeerTubeOauthClientsLocalResponse { + client_id: String, + client_secret: String, +} + +#[derive(Debug, Serialize)] +struct PeerTubeUsersToken { + client_id: String, + client_secret: String, + grant_type: String, + password: Option, + username: Option, + refresh_token: Option, +} + +#[derive(Debug, Deserialize)] +struct PeerTubeUsersTokenResponse { + refresh_token: String, + access_token: String, +} + +#[derive(Debug, Deserialize)] +struct PeerTubeVideoSourceResponse { + #[serde(rename = "fileDownloadUrl")] + pub file_download_url: String, +} + +#[derive(Debug, Deserialize)] +struct PeerTubeVideoTokenResponse { + files: PeerTubeVideoTokenResponseFiles, +} + +#[derive(Debug, Deserialize)] +struct PeerTubeVideoTokenResponseFiles { + token: String, +} + #[derive(Eq, Debug, Deserialize)] pub struct PeerTubeVideoStreamingPlaylistsFiles { pub id: u64, @@ -74,3 +117,163 @@ async fn get_video_detail(u: &str, v: &str) -> Result Result<(), Box> { + // Get client ID/secret + let oauth2_client = reqwest::get(format!("{}/api/v1/oauth-clients/local", config.base_url)) + .await? + .json::() + .await?; + + println!( + "Please type your PeerTube username for instance {}:", + config.base_url + ); + let mut username = String::new(); + stdin() + .read_line(&mut username) + .expect("Unable to read back the username!"); + + let password = prompt_password("Your password: ").expect("Unable to read back the password!"); + + let params = PeerTubeUsersToken { + client_id: oauth2_client.client_id.clone(), + client_secret: oauth2_client.client_secret.clone(), + grant_type: "password".to_string(), + username: Some(username.trim().to_string()), + password: Some(password.clone()), + refresh_token: None, + }; + + let client = Client::new(); + let oauth2_token = client + .post(format!("{}/api/v1/users/token", config.base_url)) + .form(¶ms) + .send() + .await? + .json::() + .await?; + + println!("You can now paste the following lines inside the `peertube` section of your tootube.toml file:"); + + println!(); + + println!("[peertube.oauth2]"); + println!("client_id=\"{}\"", oauth2_client.client_id); + println!("client_secret=\"{}\"", oauth2_client.client_secret); + println!("refresh_token="); + + println!(); + + println!("Finally, add the refresh token inside the refresh_token path:"); + println!("{}", oauth2_token.refresh_token); + + Ok(()) +} + +async fn get_refresh_token(config: &PeertubeConfig) -> Result> { + // unwrap is safe here, this function is only called when oauth2 is present + let oauth2_config = config.oauth2.as_ref().unwrap().clone(); + // retrieve the refresh_token from the file + let refresh_token = read_to_string(&oauth2_config.refresh_token).await?; + + debug!( + "Opened file {} to retrieve Token", + &oauth2_config.refresh_token + ); + + let params = PeerTubeUsersToken { + client_id: oauth2_config.client_id.clone(), + client_secret: oauth2_config.client_secret.clone(), + grant_type: "refresh_token".to_string(), + refresh_token: Some(refresh_token), + username: None, + password: None, + }; + + let client = Client::new(); + let oauth2_token = client + .post(format!("{}/api/v1/users/token", config.base_url)) + .form(¶ms) + .send() + .await? + .json::() + .await?; + + debug!("Retrieved access_token: {}", &oauth2_token.access_token); + + // write the new refresh token to the file + write(&oauth2_config.refresh_token, oauth2_token.refresh_token).await?; + + debug!( + "Written refresh_token to file {}", + &oauth2_config.refresh_token + ); + + Ok(oauth2_token.access_token) +} + +pub async fn get_original_video_source( + uuid: &str, + config: &PeertubeConfig, +) -> Result> { + let access_token = get_refresh_token(config).await?; + + let client = Client::new(); + + let source_vid = client + .get(format!("{}/api/v1/videos/{}/source", config.base_url, uuid)) + .header("Authorization", format!("Bearer {}", &access_token)) + .send() + .await? + .json::() + .await?; + + debug!("Got the Source Vid URL: {}", &source_vid.file_download_url); + + let video_file_token = client + .post(format!("{}/api/v1/videos/{}/token", config.base_url, uuid)) + .header("Authorization", format!("Bearer {}", &access_token)) + .send() + .await? + .json::() + .await?; + + debug!("Got the File Token: {}", &video_file_token.files.token); + + Ok(format!( + "{}?videoFileToken={}", + source_vid.file_download_url, video_file_token.files.token + )) +} + +pub async fn delete_original_video_source( + uuid: &str, + config: &PeertubeConfig, +) -> Result<(), Box> { + let access_token = get_refresh_token(config).await?; + + let client = Client::new(); + + let res = client + .delete(format!( + "{}/api/v1/videos/{}/source/file", + config.base_url, uuid + )) + .header("Authorization", format!("Bearer {}", &access_token)) + .send() + .await?; + + if !res.status().is_success() { + return Err(TootubeError::new(&format!( + "Cannot delete source video file {}: {}", + uuid, + res.text().await? + )) + .into()); + } + + Ok(()) +} diff --git a/src/youtube.rs b/src/youtube.rs index 9ac3b26..2b6194d 100644 --- a/src/youtube.rs +++ b/src/youtube.rs @@ -253,7 +253,7 @@ async fn get_playlist_ids( // if nextPageToken is present, continue the loop match local_pl.next_page_token { None => break, - Some(a) => page_token = a.clone(), + Some(a) => page_token.clone_from(&a), } }