Add support for presentations without PublishToGo

This commit is contained in:
2017-05-12 02:18:38 +02:00
parent 2826a83396
commit 3c3bf8554f
3 changed files with 234 additions and 120 deletions

65
Cargo.lock generated
View File

@@ -2,12 +2,12 @@
name = "tum_mediasite_downloader" name = "tum_mediasite_downloader"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 2.24.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -71,6 +71,14 @@ dependencies = [
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "base64"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "0.8.2" version = "0.8.2"
@@ -106,7 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.24.0" version = "2.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -121,7 +129,7 @@ dependencies = [
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.7.5" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -229,15 +237,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.10.9" version = "0.10.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -252,7 +260,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -449,16 +457,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.5.1" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -467,11 +475,6 @@ name = "rustc-demangle"
version = "0.1.4" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.1.7" version = "0.1.7"
@@ -530,28 +533,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde" name = "serde"
version = "0.9.15" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "0.9.10" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.4.2" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -742,13 +745,14 @@ dependencies = [
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80" "checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842" "checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
"checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24" "checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
"checksum bzip2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "98ce3fff84d4e90011f464bbdf48e3428f04270439f703868fd489d2aaedfc30" "checksum bzip2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "98ce3fff84d4e90011f464bbdf48e3428f04270439f703868fd489d2aaedfc30"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum clap 2.24.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f31c42d0cecb245c1a0bee00ef433eb1bf253897fe472b6a3f4202e9dbbc4b25" "checksum clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7541069be0b8aec41030802abe8b5cdef0490070afaa55418adea93b1e431e0"
"checksum cookie 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "691d39889a369dd2c7db5ed6fbd8315a8517f69dfda7a515dcc5d5b1b7d3e2d4" "checksum cookie 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6d2299f4d14d304e5ca0090207b05616110ec9cc35bba3c5c6426ba647f547d"
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec"
@@ -762,7 +766,7 @@ dependencies = [
"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77f756bed9ee3a83ce98774f4155b42a31b787029013f3a7d83eca714e500e21" "checksum httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77f756bed9ee3a83ce98774f4155b42a31b787029013f3a7d83eca714e500e21"
"checksum hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)" = "94da93321c171e26481afeebe8288757b0501901b7c5492648163d8ec4942ec5" "checksum hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "36e108e0b1fa2d17491cbaac4bc460dc0956029d10ccf83c913dd0e5db3e7f07"
"checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409" "checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409"
"checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375" "checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375"
"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
@@ -790,18 +794,17 @@ dependencies = [
"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" "checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
"checksum reqwest 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5113a267e410c17d186189940711e49da445987299763f63503cfed4dbbcccc0" "checksum reqwest 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a546e7fae4f94bd23bd818fd70d5aba0ccd5ed26221803eaf2898c358844895"
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b291854e37196c2b67249e09d6bdeff410b19e1acf05558168e9c4413b4e95" "checksum schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b291854e37196c2b67249e09d6bdeff410b19e1acf05558168e9c4413b4e95"
"checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" "checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc"
"checksum security-framework 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "42ddf098d78d0b64564b23ee6345d07573e7d10e52ad86875d89ddf5f8378a02" "checksum security-framework 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "42ddf098d78d0b64564b23ee6345d07573e7d10e52ad86875d89ddf5f8378a02"
"checksum security-framework-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "5bacdada57ea62022500c457c8571c17dfb5e6240b7c8eac5916ffa8c7138a55" "checksum security-framework-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "5bacdada57ea62022500c457c8571c17dfb5e6240b7c8eac5916ffa8c7138a55"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" "checksum serde 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "991ef6be409a3b7a46cb9ee701d86156ce851825c65dbee7f16dbd5c4e7e2d47"
"checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1" "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
"checksum serde_urlencoded 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4cde9c1d41c4852426d097c53b9151c53e314e9c6ec8a7765e083137d45c76" "checksum serde_urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a053efd81206b42661c03bbab35426b1b3a02e4e34228182108960f373639b1c"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"

View File

@@ -5,9 +5,9 @@ version = "0.1.0"
[dependencies] [dependencies]
clap = "2.20.5" clap = "2.20.5"
cookie = "0.7.0" cookie = "0.8.1"
dotenv = "0.10.0" dotenv = "0.10.0"
json = "0.11.5" json = "0.11.5"
lazy_static = "0.2.2" lazy_static = "0.2.2"
reqwest = "0.5.1" reqwest = "0.6.0"
zip = "0.2.1" zip = "0.2.1"

View File

@@ -8,6 +8,7 @@ extern crate reqwest;
extern crate zip; extern crate zip;
use std::env; use std::env;
use std::process::Command;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::{self, Read, BufReader, Write}; use std::io::{self, Read, BufReader, Write};
@@ -16,14 +17,17 @@ use std::time::{Instant, Duration};
use clap::{App, Arg}; use clap::{App, Arg};
use json::JsonValue; use json::JsonValue;
use reqwest::{Client, Response, RedirectPolicy, RequestBuilder}; use reqwest::{Client, Response, RedirectPolicy, RequestBuilder, StatusCode};
use reqwest::header::{Cookie, Charset, SetCookie}; use reqwest::header::{Cookie, Charset, SetCookie};
use reqwest::header::{ContentDisposition, DispositionType, DispositionParam}; use reqwest::header::{ContentDisposition, DispositionType, DispositionParam};
use zip::ZipArchive; use zip::ZipArchive;
use catalogs::*; use catalogs::*;
#[allow(dead_code)] // TODO: Old "Publish To Go" packages get sweeped from the server and you have to request a new one;
// Implement this
// TODO: sometimes you need to access the video listing at least once using moodle; emulate this
mod catalogs { mod catalogs {
type Login = Option<(&'static str, &'static str)>; type Login = Option<(&'static str, &'static str)>;
type CatalogDef = (&'static str, Login); type CatalogDef = (&'static str, Login);
@@ -34,8 +38,8 @@ mod catalogs {
pub const ERA: CatalogDef = ("era-2016", None); pub const ERA: CatalogDef = ("era-2016", None);
pub const GAD: CatalogDef = ("17s-grundlagen-algorithmen-und-datenstrukturen", None); pub const GAD: CatalogDef = ("17s-grundlagen-algorithmen-und-datenstrukturen", None);
pub const EIDS: CatalogDef = ("TODO", None);
pub const LA: CatalogDef = ("17s-lineare-algebra-fuer-informatik", None); pub const LA: CatalogDef = ("17s-lineare-algebra-fuer-informatik", None);
// EIST is on a Nextcloud
} }
const MAX_RETRIES: u8 = 10; const MAX_RETRIES: u8 = 10;
@@ -50,22 +54,147 @@ lazy_static! {
} }
#[derive(Debug)] #[derive(Debug)]
struct Presentation { enum Presentation {
name: String, PublishToGo {
download_url: String, name: String,
download_url: String,
},
VideoOnDemand {
name: String,
resource_id: String,
query_string: String,
}
}
impl Presentation {
fn name(&self) -> &str {
match *self {
Presentation::PublishToGo {ref name, ..} |
Presentation::VideoOnDemand {ref name, ..} => {name},
}
}
fn download(&self, presentation: &Presentation, out_dir: &Path, auth: &str) {
fn download_to_file_and_check<F: Fn(&Path) -> bool>(response: &mut Response, out_file: &Path, check: F) {
println!("Output file: {}", out_file.display());
if out_file.exists() {
if check(out_file) {
println!("Already present and valid! Skipping!");
return;
} else {
println!("Found corrupt file! Starting anew!");
}
// TODO?: We could try resuming the download if the server supports it
// http://stackoverflow.com/questions/41444297/
// http://stackoverflow.com/questions/3428102/
}
let file = download_to_file(response, &out_file);
::std::mem::drop(file);
assert!(check(out_file));
}
match *self {
Presentation::PublishToGo {ref download_url, ..} => {
let mut response =
try_to_get_valid_response(|client| {
client.get(download_url)
.header(construct_cookie(auth))
},
|resp| resp.headers().get::<ContentDisposition>().is_some());
let filename = {
let content_disposition = response.headers().get::<ContentDisposition>().unwrap();
assert_eq!(content_disposition.disposition, DispositionType::Attachment);
let mut name = None;
for param in &content_disposition.parameters {
match *param {
DispositionParam::Filename(ref charset, _, ref vec) => {
assert_eq!(&Charset::Ext("UTF-8".to_string()), charset);
name = Some(String::from_utf8(vec.to_vec())
.expect("Suggested filename isn't valid UTF-8!"));
}
_ => continue,
}
}
name.expect("Missing filename in ContentDisposition!")
};
let mut path = PathBuf::from(out_dir);
path.push(fix_filename(&filename));
download_to_file_and_check(&mut response, &path, |path| zip_is_valid(path));
},
Presentation::VideoOnDemand {ref resource_id, ref query_string, ..} => {
let videos = {
let payload = format!("{{\"getPlayerOptionsRequest\":{{\
\"ResourceId\":\"{}\",\
\"QueryString\":\"{}\"\
}}}}", resource_id, query_string);
let url = "https://streams.tum.de/Mediasite/PlayerService/PlayerService.svc/json/GetPlayerOptions";
let mut res = try_to_get_response(|client| client.post(url).header(construct_cookie(auth)).header(reqwest::header::ContentType::json()).body(&*payload));
let json_text = read_response_body(&mut res);
let json = json::parse(&json_text).expect("Failed parsing the json!");
let mut vec = Vec::new();
for stream in json["d"]["Presentation"]["Streams"].members() {
assert_eq!(stream["VideoUrls"].len(), 1);
vec.push(stream["VideoUrls"][0]["Location"].to_string());
}
vec
};
for (i, download_url) in videos.iter().enumerate() {
let mut response = try_to_get_valid_response(|client| {
client.get(download_url)
.header(construct_cookie(auth))
},
|resp| resp.status() == &StatusCode::Ok);
// TODO: Support formats besides mp4; extract extension from url or somewehre else...
let filename = format!("{} - {}.mp4", fix_filename(presentation.name()), i + 1);
let mut path = PathBuf::from(out_dir);
path.push(fix_filename(&filename));
let mut path = PathBuf::from(out_dir);
path.push(fix_filename(&filename));
download_to_file_and_check(&mut response, &path, |path| check_video(path));
}
},
}
}
} }
impl<'a> From<&'a JsonValue> for Presentation { impl<'a> From<&'a JsonValue> for Presentation {
fn from(json: &'a JsonValue) -> Presentation { fn from(json: &'a JsonValue) -> Presentation {
Presentation { if json["DownloadUrls"].len() >= 1 {
name: json["Name"] assert_eq!(json["DownloadUrls"].len(), 1);
.clone() Presentation::PublishToGo {
.take_string() name: json["Name"]
.expect("json: Presentation didn't contain a \"Name\"!"), .clone()
download_url: json["DownloadUrls"][0]["Url"] .take_string()
.clone() .expect("json: Presentation didn't contain a \"Name\"!"),
.take_string() download_url: json["DownloadUrls"][0]["Url"]
.expect("json: Presentation didn't have a download url!"), .clone()
.take_string()
.expect("json: Presentation didn't have a download url!"),
}
} else {
// No "Publish To Go" -> download video streams manually
let player_url = json["PlayerUrl"].to_string();
let index = player_url.find("?catalog=").unwrap();
let index_end_query = index + "?catalog=499c5d25-37a6-4853-95d5-bfbf7f76fcf2".len();
let index_start_resource = index - "cdf23465581b45aa92d588ebd59619d91d".len();
Presentation::VideoOnDemand {
name: json["Name"].clone().take_string().expect("json: Presentation didn't contain a \"Name\"!"),
query_string: player_url[index..index_end_query].to_string(),
resource_id: player_url[index_start_resource..index].to_string(),
}
} }
} }
} }
@@ -101,7 +230,6 @@ fn main() {
"EIDI" => EIDI, "EIDI" => EIDI,
"ERA" => ERA, "ERA" => ERA,
"GAD" => GAD, "GAD" => GAD,
"EIDS" => EIDS,
"LA" => LA, "LA" => LA,
n => { n => {
if let Some(username) = matches.value_of("username") { if let Some(username) = matches.value_of("username") {
@@ -181,8 +309,8 @@ fn download_catalog(catalog_name: &str, out_dir: &Path, auth: &str) {
println!("Downloading {}/{}: {}", println!("Downloading {}/{}: {}",
i + 1, i + 1,
presentations.len(), presentations.len(),
presentation.name); presentation.name());
download_presentation(presentation, out_dir, auth); presentation.download(presentation, out_dir, auth);
} }
} }
@@ -204,78 +332,39 @@ fn get_catalog_id(name: &str, auth: &str) -> String {
body[(idx + pre_len)..(idx + pre_len + len)].to_string() body[(idx + pre_len)..(idx + pre_len + len)].to_string()
} }
fn download_presentation(presentation: &Presentation, out_dir: &Path, auth: &str) { fn download_to_file(response: &mut Response, path: &Path) -> File {
let response = let mut file = File::create(&path).expect("Failed to create file!");
try_to_get_valid_response(|client| {
client.get(&presentation.download_url)
.header(construct_cookie(auth))
},
|resp| resp.headers().get::<ContentDisposition>().is_some());
let filename = { let mut reader = BufReader::new(response);
let content_disposition = response.headers().get::<ContentDisposition>().unwrap(); let mut buf = [0u8; 8 * 1024];
assert_eq!(content_disposition.disposition, DispositionType::Attachment);
let mut name = None; let update_duration_millis = 1000;
for param in &content_disposition.parameters { let mut last = Instant::now();
match *param { let mut done = 0;
DispositionParam::Filename(ref charset, _, ref vec) => {
assert_eq!(&Charset::Ext("UTF-8".to_string()), charset); loop {
name = Some(String::from_utf8(vec.to_vec()) let len = match reader.read(&mut buf) {
.expect("Suggested filename isn't valid UTF-8!")); Ok(0) => break,
} Ok(len) => len,
_ => continue, Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => panic!(e),
};
file.write_all(&buf[0..len]).expect("Failed writing into the file!");
done += len;
let now = Instant::now();
if now - last > Duration::from_millis(update_duration_millis) {
print!("{:.*} kB/s \r",
2,
done as f64 * 1000.0 / update_duration_millis as f64 / 1024.0);
std::io::stdout().flush().expect("Failed flushing the terminal!");
last = now;
done = 0;
} }
} }
name.expect("Missing filename in ContentDisposition!")
};
let mut path = PathBuf::from(out_dir); file
path.push(fix_filename(&filename));
println!("Output file: {}", path.display());
if path.exists() {
if zip_is_valid(&path) {
println!("Already present and valid! Skipping!");
return;
} else {
println!("Found corrupt zip! Starting anew!");
// TODO?: We could try resuming the download if the server supports it
// http://stackoverflow.com/questions/41444297/
// http://stackoverflow.com/questions/3428102/
}
}
let mut file = File::create(&path).expect("Failed to create file!");
let mut reader = BufReader::new(response);
let mut buf = [0u8; 8 * 1024];
let update_duration_millis = 1000;
let mut last = Instant::now();
let mut done = 0;
loop {
let len = match reader.read(&mut buf) {
Ok(0) => break,
Ok(len) => len,
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => panic!(e),
};
file.write_all(&buf[0..len]).expect("Failed writing into the file!");
done += len;
let now = Instant::now();
if now - last > Duration::from_millis(update_duration_millis) {
print!("{:.*} kB/s\r",
2,
done as f64 * 1000.0 / update_duration_millis as f64 / 1024.0);
std::io::stdout().flush().expect("Failed flushing the terminal!");
last = now;
done = 0;
}
}
::std::mem::drop(file);
assert!(zip_is_valid(&path));
} }
fn fix_filename(string: &str) -> String { fn fix_filename(string: &str) -> String {
@@ -295,7 +384,6 @@ fn json_to_presentations(json_str: &str) -> Vec<Presentation> {
let mut json = json::parse(json_str).expect("Failed parsing the json!"); let mut json = json::parse(json_str).expect("Failed parsing the json!");
let mut count = 0; let mut count = 0;
for presentation in json["PresentationDetailsList"].members_mut() { for presentation in json["PresentationDetailsList"].members_mut() {
assert_eq!(1, presentation["DownloadUrls"].len());
vec.push(Presentation::from(&*presentation)); vec.push(Presentation::from(&*presentation));
count += 1; count += 1;
} }
@@ -330,6 +418,29 @@ fn zip_is_valid(path: &Path) -> bool {
ZipArchive::new(file).is_ok() ZipArchive::new(file).is_ok()
} }
fn check_video(path: &Path) -> bool {
let command = Command::new("ffmpeg")
.arg("-v")
.arg("error")
.arg("-i")
.arg(path)
.arg("-f")
.arg("null")
.arg("-")
.output();
match command {
Ok(output) => {
output.stderr.is_empty()
}
Err(_) => {
println!("Failed to check {} with ffmpeg. Perhaps ffmpeg isn't in your path. \
Skipping check...", path.display());
true
}
}
}
fn try_to_get_response<F>(f: F) -> Response fn try_to_get_response<F>(f: F) -> Response
where F: Fn(&Client) -> RequestBuilder where F: Fn(&Client) -> RequestBuilder
{ {