From d8e8b9295923b751789b12224fe24ef39983f5d9 Mon Sep 17 00:00:00 2001 From: Learturely Date: Sat, 13 Jul 2024 10:11:53 +0800 Subject: [PATCH 01/14] modified: Cargo.lock --- Cargo.lock | 78 +++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0c1f9d..8272667 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,15 +385,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -dependencies = [ - "custom_derive", -] - [[package]] name = "cookie" version = "0.18.1" @@ -559,16 +550,10 @@ dependencies = [ "memchr", ] -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" - [[package]] name = "cxsign" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_internal", ] @@ -587,7 +572,7 @@ dependencies = [ [[package]] name = "cxsign_activity" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "chrono", "cxsign_captcha", @@ -605,7 +590,7 @@ dependencies = [ [[package]] name = "cxsign_captcha" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_error", "cxsign_imageproc", @@ -620,7 +605,7 @@ dependencies = [ [[package]] name = "cxsign_default_impl" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_activity", "cxsign_captcha", @@ -646,7 +631,7 @@ dependencies = [ [[package]] name = "cxsign_dir" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_error", "directories", @@ -655,7 +640,7 @@ dependencies = [ [[package]] name = "cxsign_error" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "thiserror", "ureq", @@ -664,10 +649,10 @@ dependencies = [ [[package]] name = "cxsign_imageproc" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "image", - "imageproc 0.24.0", + "imageproc", "num-traits", "ureq", ] @@ -675,7 +660,7 @@ dependencies = [ [[package]] name = "cxsign_internal" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_activity", "cxsign_captcha", @@ -697,7 +682,7 @@ dependencies = [ [[package]] name = "cxsign_login" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cookie_store", "cxsign_error", @@ -712,7 +697,7 @@ dependencies = [ [[package]] name = "cxsign_obfuscate" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_utils", "proc-macro2", @@ -722,7 +707,7 @@ dependencies = [ [[package]] name = "cxsign_pan" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "log", "mime_guess", @@ -733,7 +718,7 @@ dependencies = [ [[package]] name = "cxsign_qrcode_utils" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_imageproc", "cxsign_utils", @@ -746,7 +731,7 @@ dependencies = [ [[package]] name = "cxsign_sign" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "chrono", "cxsign_activity", @@ -765,7 +750,7 @@ dependencies = [ [[package]] name = "cxsign_signner" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_activity", "cxsign_error", @@ -777,7 +762,7 @@ dependencies = [ [[package]] name = "cxsign_store" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_dir", "cxsign_error", @@ -790,7 +775,7 @@ dependencies = [ [[package]] name = "cxsign_types" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cxsign_dir", "cxsign_error", @@ -807,7 +792,7 @@ dependencies = [ [[package]] name = "cxsign_user" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "cookie_store", "cxsign_dir", @@ -822,7 +807,7 @@ dependencies = [ [[package]] name = "cxsign_utils" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#48f037d78d090edb98063d5921161d0c3330830e" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" dependencies = [ "chrono", "flate2", @@ -1244,25 +1229,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "imageproc" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0d7770f428b4615960cc8602775d1f04c75d41b0ccdef862e889ebaae9bbf" -dependencies = [ - "ab_glyph", - "approx", - "conv", - "getrandom", - "image", - "itertools", - "nalgebra", - "num", - "rand", - "rand_distr", - "rayon", -] - [[package]] name = "imageproc" version = "0.25.0" @@ -2159,7 +2125,7 @@ dependencies = [ "encoding", "fancy-regex", "image", - "imageproc 0.25.0", + "imageproc", "multimap", "num", "once_cell", @@ -2988,9 +2954,9 @@ dependencies = [ [[package]] name = "xcap" -version = "0.0.9" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b76339b2f4195ad7092d88a19819cd99fe15351f0cf82041c42afa8a33efd60" +checksum = "a462fc23e8aab59b6dbd7d717999d4589374ef94142005143e40740187847ccb" dependencies = [ "core-foundation", "core-graphics", From 68a3c1fb8cf516452921bc3fcf184b71d3b96ee4 Mon Sep 17 00:00:00 2001 From: Learturely Date: Sat, 13 Jul 2024 10:21:31 +0800 Subject: [PATCH 02/14] modified: Cargo.lock --- Cargo.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8272667..f33e8b4 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,7 +553,7 @@ dependencies = [ [[package]] name = "cxsign" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_internal", ] @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "cxsign_activity" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "chrono", "cxsign_captcha", @@ -590,7 +590,7 @@ dependencies = [ [[package]] name = "cxsign_captcha" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_error", "cxsign_imageproc", @@ -605,7 +605,7 @@ dependencies = [ [[package]] name = "cxsign_default_impl" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_activity", "cxsign_captcha", @@ -631,7 +631,7 @@ dependencies = [ [[package]] name = "cxsign_dir" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_error", "directories", @@ -640,7 +640,7 @@ dependencies = [ [[package]] name = "cxsign_error" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "thiserror", "ureq", @@ -649,7 +649,7 @@ dependencies = [ [[package]] name = "cxsign_imageproc" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "image", "imageproc", @@ -660,7 +660,7 @@ dependencies = [ [[package]] name = "cxsign_internal" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_activity", "cxsign_captcha", @@ -682,7 +682,7 @@ dependencies = [ [[package]] name = "cxsign_login" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cookie_store", "cxsign_error", @@ -697,7 +697,7 @@ dependencies = [ [[package]] name = "cxsign_obfuscate" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_utils", "proc-macro2", @@ -707,7 +707,7 @@ dependencies = [ [[package]] name = "cxsign_pan" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "log", "mime_guess", @@ -718,7 +718,7 @@ dependencies = [ [[package]] name = "cxsign_qrcode_utils" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_imageproc", "cxsign_utils", @@ -731,7 +731,7 @@ dependencies = [ [[package]] name = "cxsign_sign" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "chrono", "cxsign_activity", @@ -750,7 +750,7 @@ dependencies = [ [[package]] name = "cxsign_signner" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_activity", "cxsign_error", @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "cxsign_store" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_dir", "cxsign_error", @@ -775,7 +775,7 @@ dependencies = [ [[package]] name = "cxsign_types" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cxsign_dir", "cxsign_error", @@ -792,7 +792,7 @@ dependencies = [ [[package]] name = "cxsign_user" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "cookie_store", "cxsign_dir", @@ -807,7 +807,7 @@ dependencies = [ [[package]] name = "cxsign_utils" version = "0.2.0" -source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#8965ecc883d1035f3ab66fda9c61cf5880906a22" +source = "git+https://github.com/worksoup/newsign.git?branch=dev-v0.2#42fc94eb672de4793c2fe890ed83e89f262152ff" dependencies = [ "chrono", "flate2", From d3967c763812265772f68222f12f61f991a0d0c9 Mon Sep 17 00:00:00 2001 From: learturely Date: Thu, 25 Apr 2024 18:55:12 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E3=80=82=E6=B7=BB=E5=8A=A0=E4=BD=8D=E7=BD=AE=E9=A2=84=E5=A4=84?= =?UTF-8?q?=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/mod.rs | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/data/mod.rs diff --git a/src/data/mod.rs b/src/data/mod.rs new file mode 100644 index 0000000..fc74c63 --- /dev/null +++ b/src/data/mod.rs @@ -0,0 +1,178 @@ +use std::collections::HashMap; +use cxsign::{Location, LocationPreprocessorTrait}; +use lazy_static::lazy_static; +use serde::Deserialize; + +#[derive(Deserialize)] +struct LocationWithoutAlt { + latitude: f64, + longitude: f64, + address: String, +} + +impl LocationWithoutAlt { + fn to_location(&self, alt: &str) -> Location { + Location::new(&self.address, &format!("{:.6}", self.longitude), &format!("{:.6}", self.latitude), alt) + } +} + +/// See [here](https://github.com/Pairman/Xdcheckin/blob/main/src/xdcheckin/core/locations.py). +static LOCATIONS_JSON: &str = r#" +{ + "A楼": { + "latitude": 34.133171, + "longitude": 108.837420, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "B楼": { + "latitude": 34.132297, + "longitude": 108.838367, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "C楼": { + "latitude": 34.131125, + "longitude": 108.838983, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "D楼": { + "latitude": 34.130856, + "longitude": 108.841579, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "EI楼": { + "latitude": 34.130878, + "longitude": 108.839863, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "EII楼": { + "latitude": 34.130856, + "longitude": 108.841579, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "EIII楼": { + "latitude": 34.130056, + "longitude": 108.843268, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "F楼": { + "latitude": 34.130654, + "longitude": 108.843016, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "G楼": { + "latitude": 34.129660, + "longitude": 108.845244, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + }, + "信远楼": { + "latitude": 34.131640, + "longitude": 108.845415, + "address": "西安市长安区兴隆街道外环北路西安电子科技大学(南校区)" + }, + "图书馆": { + "latitude": 34.131125, + "longitude": 108.838983, + "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" + }, + "大学生活动中心": { + "latitude": 34.134972, + "longitude": 108.835282, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "北操场": { + "latitude": 34.137362, + "longitude": 108.837906, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "北篮球场": { + "latitude": 34.134972, + "longitude": 108.835282, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "北乒乓球场": { + "latitude": 34.134972, + "longitude": 108.835282, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "游泳中心": { + "latitude": 34.134972, + "longitude": 108.835282, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "南操场": { + "latitude": 34.132559, + "longitude": 108.832542, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "南篮球场": { + "latitude": 34.128472, + "longitude": 108.832443, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "南乒乓球场": { + "latitude": 34.129376, + "longitude": 108.834375, + "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" + }, + "远望谷体育馆": { + "latitude": 34.126418, + "longitude": 108.844544, + "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" + }, + "博物馆": { + "latitude": 34.125589, + "longitude": 108.844337, + "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" + }, + "网安大楼": { + "latitude": 34.128353, + "longitude": 108.842010, + "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" + }, + "礼仪广场": { + "latitude": 34.132006, + "longitude": 108.842118, + "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" + } +} +"#; +lazy_static! { + static ref LOCATIONS_WITHOUT_ALT: HashMap< String, LocationWithoutAlt > + = serde_json::from_str(LOCATIONS_JSON).unwrap(); + pub static ref ADDRS: HashMap< String, String > + = LOCATIONS_WITHOUT_ALT.iter().map(|(k,v)|(k.clone(),v.address.clone())).collect(); + pub static ref LOCATIONS: HashMap< String, Location > + = LOCATIONS_WITHOUT_ALT.iter().map(|(k,v)|(k.clone(),v.to_location("1108"))).collect(); +} +pub struct LocationPreprocessor; + +impl LocationPreprocessorTrait for LocationPreprocessor { + fn do_preprocess(&self, location: Location) -> Location { + let [mut addr, lon, lat, alt] = location.to_owned_fields(); + for (k, v) in ADDRS.iter() { + if addr.starts_with(k.trim_matches('楼')) { + addr = v.to_string(); + } + } + #[cfg(debug_assertions)] + if addr.contains("菜鸟驿站") { + addr = "TEST".to_string(); + } + Location::from_owned_fields([addr, lon, lat, alt]) + } +} + +#[cfg(test)] +mod tests { + use crate::data::{ADDRS, LOCATIONS}; + + #[test] + fn print_addrs() { + println!("{:?}", ADDRS.keys().collect::>()); + } + + #[test] + fn print_locations() { + println!("{:?}", LOCATIONS.values().collect::>()); + } +} \ No newline at end of file From ad11640ca25adfa4af4780e84c183ae5dbda6de8 Mon Sep 17 00:00:00 2001 From: learturely Date: Thu, 25 Apr 2024 20:19:07 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E5=B0=86=20data=20=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E6=96=B0=E5=BA=93=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/mod.rs | 178 ------------------------------------------------ 1 file changed, 178 deletions(-) delete mode 100644 src/data/mod.rs diff --git a/src/data/mod.rs b/src/data/mod.rs deleted file mode 100644 index fc74c63..0000000 --- a/src/data/mod.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::collections::HashMap; -use cxsign::{Location, LocationPreprocessorTrait}; -use lazy_static::lazy_static; -use serde::Deserialize; - -#[derive(Deserialize)] -struct LocationWithoutAlt { - latitude: f64, - longitude: f64, - address: String, -} - -impl LocationWithoutAlt { - fn to_location(&self, alt: &str) -> Location { - Location::new(&self.address, &format!("{:.6}", self.longitude), &format!("{:.6}", self.latitude), alt) - } -} - -/// See [here](https://github.com/Pairman/Xdcheckin/blob/main/src/xdcheckin/core/locations.py). -static LOCATIONS_JSON: &str = r#" -{ - "A楼": { - "latitude": 34.133171, - "longitude": 108.837420, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "B楼": { - "latitude": 34.132297, - "longitude": 108.838367, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "C楼": { - "latitude": 34.131125, - "longitude": 108.838983, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "D楼": { - "latitude": 34.130856, - "longitude": 108.841579, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "EI楼": { - "latitude": 34.130878, - "longitude": 108.839863, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "EII楼": { - "latitude": 34.130856, - "longitude": 108.841579, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "EIII楼": { - "latitude": 34.130056, - "longitude": 108.843268, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "F楼": { - "latitude": 34.130654, - "longitude": 108.843016, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "G楼": { - "latitude": 34.129660, - "longitude": 108.845244, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - }, - "信远楼": { - "latitude": 34.131640, - "longitude": 108.845415, - "address": "西安市长安区兴隆街道外环北路西安电子科技大学(南校区)" - }, - "图书馆": { - "latitude": 34.131125, - "longitude": 108.838983, - "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" - }, - "大学生活动中心": { - "latitude": 34.134972, - "longitude": 108.835282, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "北操场": { - "latitude": 34.137362, - "longitude": 108.837906, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "北篮球场": { - "latitude": 34.134972, - "longitude": 108.835282, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "北乒乓球场": { - "latitude": 34.134972, - "longitude": 108.835282, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "游泳中心": { - "latitude": 34.134972, - "longitude": 108.835282, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "南操场": { - "latitude": 34.132559, - "longitude": 108.832542, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "南篮球场": { - "latitude": 34.128472, - "longitude": 108.832443, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "南乒乓球场": { - "latitude": 34.129376, - "longitude": 108.834375, - "address": "西安市长安区兴隆街道梧桐大道西安电子科技大学(南校区)" - }, - "远望谷体育馆": { - "latitude": 34.126418, - "longitude": 108.844544, - "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" - }, - "博物馆": { - "latitude": 34.125589, - "longitude": 108.844337, - "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" - }, - "网安大楼": { - "latitude": 34.128353, - "longitude": 108.842010, - "address": "西安市长安区兴隆街道内环南路西安电子科技大学(南校区)" - }, - "礼仪广场": { - "latitude": 34.132006, - "longitude": 108.842118, - "address": "西安市长安区兴隆街道内环北路西安电子科技大学(南校区)" - } -} -"#; -lazy_static! { - static ref LOCATIONS_WITHOUT_ALT: HashMap< String, LocationWithoutAlt > - = serde_json::from_str(LOCATIONS_JSON).unwrap(); - pub static ref ADDRS: HashMap< String, String > - = LOCATIONS_WITHOUT_ALT.iter().map(|(k,v)|(k.clone(),v.address.clone())).collect(); - pub static ref LOCATIONS: HashMap< String, Location > - = LOCATIONS_WITHOUT_ALT.iter().map(|(k,v)|(k.clone(),v.to_location("1108"))).collect(); -} -pub struct LocationPreprocessor; - -impl LocationPreprocessorTrait for LocationPreprocessor { - fn do_preprocess(&self, location: Location) -> Location { - let [mut addr, lon, lat, alt] = location.to_owned_fields(); - for (k, v) in ADDRS.iter() { - if addr.starts_with(k.trim_matches('楼')) { - addr = v.to_string(); - } - } - #[cfg(debug_assertions)] - if addr.contains("菜鸟驿站") { - addr = "TEST".to_string(); - } - Location::from_owned_fields([addr, lon, lat, alt]) - } -} - -#[cfg(test)] -mod tests { - use crate::data::{ADDRS, LOCATIONS}; - - #[test] - fn print_addrs() { - println!("{:?}", ADDRS.keys().collect::>()); - } - - #[test] - fn print_locations() { - println!("{:?}", LOCATIONS.values().collect::>()); - } -} \ No newline at end of file From 5a028e876dded6893f9b791cc2fa6103f342e209 Mon Sep 17 00:00:00 2001 From: learturely Date: Mon, 29 Apr 2024 21:24:09 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E6=95=B0=E6=8D=AE=E5=BA=93=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main.rs b/src/main.rs index c2b2586..d5702f2 100755 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod cli; // #[global_allocator] // static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +use crate::cli::location::database_add_location; use cli::arg::{AccountSubCommand, Args, MainCommand}; use cxsign::{ activity::{Activity, RawSign}, @@ -72,6 +73,14 @@ fn main() { db.add_table::(); db.add_table::(); db.add_table::(); + for (s, l) in xdsign_data::LOCATIONS.iter() { + let alias_table = AliasTable::from_ref(&db); + let location_table = LocationTable::from_ref(&db); + if !alias_table.has_alias(s) { + let lid = database_add_location(&location_table, -1, l); + alias_table.add_alias_or(s, lid, |_, _, _| {}) + } + } if let Some(sub_cmd) = command { match sub_cmd { MainCommand::Account { command } => { From 6e1c13c3e31933bf8e84c9db24f233d8ab7d54b8 Mon Sep 17 00:00:00 2001 From: learturely Date: Tue, 7 May 2024 21:25:27 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E5=B0=86=20xddcc=20=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E5=AD=90=E5=91=BD=E4=BB=A4=E6=B7=BB=E5=8A=A0=E8=87=B3=20xdsign?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli/arg.rs | 20 +++++ src/xddcc/live.rs | 134 ++++++++++++++++++++++++++++++ src/xddcc/mod.rs | 100 ++++++++++++++++++++++ src/xddcc/protocol.rs | 49 +++++++++++ src/xddcc/room.rs | 162 ++++++++++++++++++++++++++++++++++++ src/xddcc/tools.rs | 189 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 654 insertions(+) create mode 100644 src/xddcc/live.rs create mode 100644 src/xddcc/mod.rs create mode 100644 src/xddcc/protocol.rs create mode 100644 src/xddcc/room.rs create mode 100644 src/xddcc/tools.rs diff --git a/src/cli/arg.rs b/src/cli/arg.rs index bf27d6d..1956351 100644 --- a/src/cli/arg.rs +++ b/src/cli/arg.rs @@ -122,6 +122,26 @@ pub enum MainCommand { }, /// 显示配置文件夹位置。 WhereIsConfig, + Xddcc { + /// 获取特定账号下节课的直播信息,格式为以半角逗号隔开的字符串。 + #[arg(short, long)] + accounts: Option, + /// 覆盖默认行为至获取当前课的直播信息。 + #[arg(short, long)] + this: bool, + /// 通过 `device_code` 获取直播信息。 + #[arg(short, long)] + device_code: Option, + /// 导出文件路径。可选提供。 + #[arg(short, long)] + output: Option, + /// 列出所有设备码。 + #[arg(short, long)] + list: bool, + // /// 网页播放器地址。 + // #[arg(short, long)] + // web: bool, + }, } #[derive(Subcommand, Debug)] diff --git a/src/xddcc/live.rs b/src/xddcc/live.rs new file mode 100644 index 0000000..8319833 --- /dev/null +++ b/src/xddcc/live.rs @@ -0,0 +1,134 @@ +use std::collections::{HashMap, HashSet}; + +use cxsign::Session; +use indicatif::MultiProgress; +use serde::{Deserialize, Serialize}; + +use crate::xddcc::{room::Room, tools::VideoPath}; + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct Live { + place: String, + id: i64, + #[serde(rename = "weekDay")] + week_day: u32, + jie: i32, +} +impl Live { + pub fn get_id(&self) -> String { + self.id.to_string() + } + pub fn get_week_day(&self) -> u32 { + self.week_day + } + fn get_jie(&self) -> i32 { + self.jie + } + pub fn get_lives( + session: &Session, + week: i64, + term_year: i32, + term: i32, + ) -> Result, ureq::Error> { + let vec = + crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? + .into_json::>() + .unwrap(); + let mut map = HashMap::new(); + for i in vec { + map.insert(i.place, i.id); + } + Ok(map) + } + fn get_lives_by_time( + session: &Session, + term_year: i32, + term: i32, + week: i64, + week_day: u32, + jie: i32, + ) -> Result, ureq::Error> { + let vec = + crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? + .into_json::>() + .unwrap(); + let iter = vec + .into_iter() + .filter(|live| (live.get_week_day() == week_day) && (live.get_jie() >= jie)); + let mut vec = iter.collect::>(); + vec.sort_by(|l1, l2| l1.get_jie().cmp(&l2.get_jie())); + Ok(vec.first().cloned()) + } + pub fn get_lives_now<'a, Iter: Iterator + Clone>( + sessions: Iter, + this: bool, + multi: &MultiProgress, + ) -> HashMap<&'a str, (&'a str, Room, VideoPath)> { + let sessions = sessions.collect::>(); + let total = sessions.len() as u64; + let data_time = chrono::DateTime::::from(std::time::SystemTime::now()); + let mut term_year = 0; + let mut term = 0; + let mut week = 0; + let mut first = true; + let week_day = chrono::Datelike::weekday(&data_time).number_from_monday(); + let mut lives_map = HashMap::new(); + let sty = indicatif::ProgressStyle::with_template( + "获取直播号:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap(); + let pb = multi.add(indicatif::ProgressBar::new(total)); + pb.set_style(sty); + for session in sessions.clone() { + if first { + (term_year, term, week) = crate::xddcc::tools::term_year_detial(session); + first = false; + } + let jie = crate::xddcc::tools::now_to_jie(this); + let live = Live::get_lives_by_time(session, term_year, term, week, week_day, jie); + if let Ok(Some(live)) = live { + lives_map.insert(session, live); + } + pb.inc(1) + } + pb.finish_with_message("获取直播号完成。"); + multi.remove(&pb); + let mut lives = HashSet::new(); + for live in lives_map.values() { + lives.insert(live.get_id()); + } + let mut rooms = HashMap::new(); + let sty = indicatif::ProgressStyle::with_template( + "获取地址中:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap(); + let pb = multi.add(indicatif::ProgressBar::new(lives.len() as u64 * 2)); + pb.set_style(sty); + pb.inc(0); + for session in sessions.clone() { + for live in lives { + if let Some(room) = Room::get_rooms(session, &live).unwrap() { + pb.inc(1); + let video_path = room.get_live_video_path(session); + pb.inc(1); + rooms.insert(live, (room, video_path)); + } else { + pb.inc(2); + } + } + break; + } + pb.finish_with_message("已获取直播地址。"); + multi.remove(&pb); + let mut results = HashMap::new(); + for (session, live) in lives_map { + if let Some((room, video_path)) = rooms.get(&live.get_id()) { + results.insert( + session.get_uid(), + (session.get_stu_name(), room.clone(), video_path.clone()), + ); + } + } + results + } +} diff --git a/src/xddcc/mod.rs b/src/xddcc/mod.rs new file mode 100644 index 0000000..9a3d583 --- /dev/null +++ b/src/xddcc/mod.rs @@ -0,0 +1,100 @@ +mod live; +mod protocol; +mod room; +mod tools; + +use crate::xddcc::{live::Live, room::Room, tools::PairVec}; +use clap::Parser; +use cxsign::store::tables::AccountTable; +use indicatif::MultiProgress; +use std::path::PathBuf; +use log::warn; + +#[derive(Parser, Debug)] +#[command(author, version, about = "获取直播信息。")] +pub struct XddccSubCommand { + /// 获取特定账号下节课的直播信息,格式为以半角逗号隔开的字符串。 + #[arg(short, long)] + pub accounts: Option, + /// 覆盖默认行为至获取当前课的直播信息。 + #[arg(short, long)] + pub this: bool, + /// 通过 `device_code` 获取直播信息。 + #[arg(short, long)] + pub device_code: Option, + /// 导出文件路径。可选提供。 + #[arg(short, long)] + pub output: Option, + /// 列出所有设备码。 + #[arg(short, long)] + pub list: bool, + // /// 网页播放器地址。 + // #[arg(short, long)] + // pub web: bool, +} +pub fn xddcc( + accounts: Option, + this: bool, + device_code: Option, + output: Option, + list: bool, + table: &AccountTable, + multi: &MultiProgress, +) { + if list { + if device_code.is_some() { + warn!("多余的参数: `-d, --device-code`.") + } + if this { + warn!("多余的参数: `-t, --this`.") + } + // if web { + // warn!("多余的参数: `-w, --web`.") + // } + let sessions = if let Some(accounts) = accounts { + table.get_sessions_by_accounts_str(&accounts) + } else { + table.get_sessions() + }; + if sessions.len() == 0 { + warn!("请至少登录一个账号!"); + } + let rooms = tools::map_sort_by_key(Room::get_all_rooms(sessions.values(), multi)); + tools::out(&PairVec::new(rooms), output) + } else if let Some(device_code) = device_code { + if accounts.is_some() { + warn!("多余的参数: `-a, --accounts`.") + } + if this { + warn!("多余的参数: `-t, --this`.") + } + let sessions = table.get_sessions(); + if sessions.len() == 0 { + warn!("未有登录的账号!"); + } + for session in sessions.values() { + tools::out( + &tools::get_live_video_path(session, &device_code), + output.clone(), + ); + break; + } + } else { + let sessions = if let Some(accounts) = accounts { + table.get_sessions_by_accounts_str(&accounts) + } else { + table.get_sessions() + }; + if sessions.len() == 0 { + warn!("未有登录的账号!"); + } + tools::out( + &PairVec::new(tools::map_sort_by_key(Live::get_lives_now( + sessions.values(), + this, + multi, + ))), + output.clone(), + ); + } +} diff --git a/src/xddcc/protocol.rs b/src/xddcc/protocol.rs new file mode 100644 index 0000000..f451287 --- /dev/null +++ b/src/xddcc/protocol.rs @@ -0,0 +1,49 @@ +use cxsign::Session; +use ureq::{Agent, Response}; + +static LIST_STUDENT_COURSE_LIVE_PAGE: &str = + "http://newesxidian.chaoxing.com/frontLive/listStudentCourseLivePage"; +pub fn list_student_course_live_page( + session: &Session, + week: i64, + term_year: i32, + term: i32, +) -> Result { + let url = format!( + "{LIST_STUDENT_COURSE_LIVE_PAGE}?fid=16820&userId={}&week={week}&termYear={term_year}&termId={term}&type=1", + session.get_uid(), + ); + session.get(&url).call() +} +static LIST_SINGLE_COURSE: &str = "http://newesxidian.chaoxing.com/live/listSignleCourse"; +pub fn list_single_course(session: &Session, live_id: &str) -> Result { + let url = format!( + "{LIST_SINGLE_COURSE}?fid=16820&liveId={live_id}&uId={}", + session.get_uid() + ); + session.get(&url).call() +} + +static GET_VIEW_URL: &str = "http://newesxidian.chaoxing.com/live/getViewUrlNoCourseLive"; +pub fn get_live_url(agent: &Agent, device_conde: &str) -> Result { + let url = format!("{GET_VIEW_URL}?deviceCode={device_conde}&status=1&fid=16820"); + agent.get(&url).call() +} +// pub fn get_recording_url( +// agent: &Agent, +// device_conde: &str, +// start_time: &str, +// end_time: &str, +// ) -> Result { +// let url = format!("{GET_VIEW_URL}?deviceCode={device_conde}&status=2&fid=16820&startTime={start_time}&endTime={end_time}"); +// agent.get(&url).call() +// } +static GET_WEEK_DETAIL: &str = "http://newesxidian.chaoxing.com/frontLive/getWeekDetail"; +pub fn get_week_detail( + agent: &Agent, + week: i32, + semester_id: i32, +) -> Result { + let url = format!("{GET_WEEK_DETAIL}?week={week}&semesterId={semester_id}"); + agent.get(&url).call() +} diff --git a/src/xddcc/room.rs b/src/xddcc/room.rs new file mode 100644 index 0000000..d074d8c --- /dev/null +++ b/src/xddcc/room.rs @@ -0,0 +1,162 @@ +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +use chrono::{Datelike, Local}; +use cxsign::Session; +use indicatif::MultiProgress; +use serde::{Deserialize, Serialize}; + +use crate::xddcc::{live::Live, tools::VideoPath}; + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct Room { + #[serde(rename = "schoolRoomName")] + name: String, + #[serde(rename = "deviceCode")] + device_code: String, + #[serde(rename = "schoolRoomId")] + room_id: i32, + id: i32, +} +impl Room { + fn trim(mut self) -> Self { + self.name = self.name.trim().to_owned(); + self + } + pub fn get_live_video_path(&self, session: &Session) -> VideoPath { + crate::xddcc::tools::get_live_video_path(session, &self.device_code) + } + // pub fn get_live_video_path(&self, session: &Session) -> VideoPath { + // crate::tools::get_live_video_path(session, &self.device_code) + // } + // pub fn get_live_url(&self, session: &Session) -> WebUrl { + // crate::tools::get_live_web_url(session, &self.device_code) + // } + pub fn get_rooms(session: &Session, live_id: &str) -> Result, ureq::Error> { + let rooms: Vec = crate::xddcc::protocol::list_single_course(session, live_id)? + .into_json() + .unwrap(); + Ok(rooms + .into_iter() + .find(|r| r.id.to_string() == live_id) + .map(|r| r.trim())) + } + pub fn get_all_rooms<'a, Iter: Iterator + Clone>( + sessions: Iter, + multi: &MultiProgress, + ) -> HashMap { + let map = Arc::new(Mutex::new(HashMap::new())); + Room::get_all_live_id(&sessions.clone().collect(), Arc::clone(&map), multi); + let rooms = Arc::new(Mutex::new(HashMap::new())); + for session in sessions { + Room::id_to_rooms(map.clone(), (*session).clone(), rooms.clone(), multi); + break; + } + Arc::into_inner(rooms).unwrap().into_inner().unwrap() + } + pub fn get_all_live_id( + sessions: &Vec<&Session>, + id_map: Arc>>, + multi: &MultiProgress, + ) { + let now_year = Local::now().year(); + let thread_count = 64 / sessions.len() as i32; + let week_total = 6 * 60; + let total = week_total * sessions.len() as i32; + let sty = indicatif::ProgressStyle::with_template( + "获取直播号:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap(); + let pb = multi.add(indicatif::ProgressBar::new(total as u64)); + pb.set_style(sty); + let pb = Arc::new(Mutex::new(pb)); + let mut handles = Vec::new(); + for session in sessions.into_iter() { + let week_thread = week_total / (thread_count - 1) + 1; + let thread_count = week_total / week_thread + 1; + let week_rest = week_total % week_thread; + for i in 0..thread_count { + let session = (*session).clone(); + let id_map = Arc::clone(&id_map); + let pb = Arc::clone(&pb); + let handle = std::thread::spawn(move || { + for date_count in i * week_thread..if i != thread_count - 1 { + (i + 1) * week_thread + } else { + i * week_thread + week_rest + } { + let (year, term, week) = + crate::xddcc::tools::date_count_to_year_term_week(now_year, date_count); + let lives = Live::get_lives(&session, week, year, term).unwrap(); + for live in lives { + id_map.lock().unwrap().insert(live.0, live.1); + } + pb.lock().unwrap().inc(1) + } + }); + handles.push(handle); + } + } + for handle in handles { + handle.join().unwrap(); + } + let pb = Arc::into_inner(pb).unwrap().into_inner().unwrap(); + pb.finish_with_message("获取直播号完成。"); + multi.remove(&pb); + } + pub fn id_to_rooms( + id_map: Arc>>, + session: Session, + rooms: Arc>>, + multi: &MultiProgress, + ) { + let ids = id_map + .lock() + .unwrap() + .values() + .map(|a| *a) + .collect::>(); + let len = ids.len() as i32; + let total = len; + let sty = indicatif::ProgressStyle::with_template( + "获取设备码:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap(); + let pb = multi.add(indicatif::ProgressBar::new(total as u64)); + pb.set_style(sty); + let pb = Arc::new(Mutex::new(pb)); + let thread_count = 64; + let chunk_rest = len % thread_count; + let chunk_count = len / thread_count + if chunk_rest == 0 { 0 } else { 1 }; + for i in 0..chunk_count { + let mut handles = Vec::new(); + let ids = &ids[(i * thread_count) as usize..if i != chunk_count - 1 { + (i + 1) * thread_count + } else { + len + } as usize]; + for id in ids { + let id = *id; + let session = session.clone(); + let rooms = rooms.clone(); + let pb = Arc::clone(&pb); + let handle = std::thread::spawn(move || { + let room = Room::get_rooms(&session, id.to_string().as_str()).unwrap(); + if let Some(room) = room { + rooms.lock().unwrap().insert(room.name, room.device_code); + } + pb.lock().unwrap().inc(1); + }); + handles.push(handle) + } + for handle in handles { + handle.join().unwrap(); + } + } + let pb = Arc::into_inner(pb).unwrap().into_inner().unwrap(); + pb.finish_with_message("获取设备码完成。"); + multi.remove(&pb); + } +} diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs new file mode 100644 index 0000000..f405d44 --- /dev/null +++ b/src/xddcc/tools.rs @@ -0,0 +1,189 @@ +use chrono::{Local, Timelike}; +use cxsign::Session; +use log::info; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, hash::Hash}; + +#[derive(Serialize, Default, Debug, Clone)] +pub struct VideoPath { + ppt_video: Option, + teacher_full: Option, + teacher_track: Option, + student_full: Option, +} +#[derive(Serialize, Default, Debug, Clone)] +struct WebUrl { + url: String, +} +fn web_url_to_video_path(url: &WebUrl) -> VideoPath { + let url = &url.url.split("?info=").collect::>()[1]; + let url = percent_encoding::percent_decode_str(url) + .decode_utf8() + .unwrap() + .to_string(); + #[derive(Deserialize)] + struct VideoPathInternal { + #[serde(rename = "pptVideo")] + ppt_video: Option, + #[serde(rename = "teacherFull")] + teacher_full: Option, + #[serde(rename = "teacherTrack")] + teacher_track: Option, + #[serde(rename = "studentFull")] + student_full: Option, + } + #[derive(Deserialize)] + struct Info { + #[serde(rename = "videoPath")] + video_path: VideoPathInternal, + } + let Info { + video_path: + VideoPathInternal { + ppt_video, + teacher_full, + teacher_track, + student_full, + }, + } = ureq::serde_json::from_str(&url).unwrap(); + VideoPath { + ppt_video, + teacher_full, + teacher_track, + student_full, + } +} +fn get_live_web_url(session: &Session, device_code: &str) -> WebUrl { + let url = crate::xddcc::protocol::get_live_url(&session, &device_code) + .unwrap() + .into_string() + .unwrap(); + WebUrl { url } +} +pub fn get_live_video_path(session: &Session, device_code: &str) -> VideoPath { + let url = get_live_web_url(session, device_code); + web_url_to_video_path(&url) +} +pub fn year_to_semester_id(year: i32, term: i32) -> i32 { + let mut r = 2 * year - 4035 + term; + if year == 2018 { + r -= 1; + } else if r < 1 { + r = 1; + } + r +} +pub fn date_count_to_year_term_week(now_year: i32, date_count: i32) -> (i32, i32, i64) { + ( + now_year - 6 + (date_count / 30) % 2 + date_count / 60, + 2 - (date_count / 30) % 2, + date_count as i64 % 30 + 1, + ) +} +// pub fn out(contents: &S, path: Option) { +// let contents = toml::to_string_pretty(contents).unwrap(); +// if let Some(path) = path { +// std::fs::write(path, contents).expect("写入内容出错!"); +// } else { +// debug!("{contents}") +// } +// } +pub fn now_to_jie(this: bool) -> i32 { + fn now_to_jie_internal() -> i32 { + let date_time = Local::now(); + let s1 = Local::now().with_hour(8).unwrap().with_minute(30).unwrap(); + let s3 = Local::now().with_hour(10).unwrap().with_minute(25).unwrap(); + let s5 = Local::now().with_hour(14).unwrap().with_minute(0).unwrap(); + let s7 = Local::now().with_hour(15).unwrap().with_minute(55).unwrap(); + let s9 = Local::now().with_hour(19).unwrap().with_minute(0).unwrap(); + if date_time < s1 { + -1 + } else if date_time >= s1 && date_time < s3 { + 1 + } else if date_time >= s3 && date_time < s5 { + 3 + } else if date_time >= s5 && date_time < s7 { + 5 + } else if date_time >= s7 && date_time < s9 { + 7 + } else { + 9 + } + } + if !this { + now_to_jie_internal() + 2 + } else { + now_to_jie_internal() + } +} +pub fn map_sort_by_key(map: HashMap) -> Vec<(K, V)> { + let mut map = map.into_iter().collect::>(); + map.sort_by(|x, y| x.0.cmp(&y.0)); + map.into_iter().collect() +} +pub fn term_year_detial(session: &Session) -> (i32, i32, i64) { + let data_time = chrono::DateTime::::from(std::time::SystemTime::now()); + let year = chrono::Datelike::year(&data_time); + let semester_id = year_to_semester_id(year - 1, 2); + + #[derive(Deserialize)] + struct WeekDetail { + date1: String, + } + let WeekDetail { date1, .. } = + crate::xddcc::protocol::get_week_detail(&session, 1, semester_id) + .unwrap() + .into_json() + .unwrap(); + let date = date1.split('-').map(|s| s.trim()).collect::>(); + let month = date[0].parse::().unwrap(); + let day = date[1].parse::().unwrap(); + let term_begin_data_time = as std::str::FromStr>::from_str( + &format!("{year}-{month}-{day}T00:00:00.0+08:00"), + ) + .unwrap(); + let week = data_time + .signed_duration_since(&term_begin_data_time) + .num_weeks() + + 1; + let (term_year, term) = if chrono::Datelike::month(&data_time) * 100 + + chrono::Datelike::day(&data_time) + > month * 100 + day + && chrono::Datelike::month(&data_time) * 100 + chrono::Datelike::day(&data_time) < 700 + { + (year - 1, 2) + } else { + (year, 1) + }; + (term_year, term, week) +} + +pub struct PairVec { + vec: Vec<(K, V)>, +} +impl PairVec { + pub fn new(vec: Vec<(K, V)>) -> Self { + Self { vec } + } +} +impl Serialize for PairVec { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(self.vec.len()))?; + for (k, v) in &self.vec { + map.serialize_entry(k, v)?; + } + map.end() + } +} +pub fn out(contents: &S, path: Option) { + let contents = serde_json::to_string_pretty(contents).unwrap(); + if let Some(path) = path { + std::fs::write(path, contents).expect("写入内容出错!"); + } else { + info!("{contents}") + } +} From abfbb2d35feb95dcbf4858179d3e8f6b4ca2ae87 Mon Sep 17 00:00:00 2001 From: learturely Date: Tue, 7 May 2024 21:29:24 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=EF=BC=9B=E6=8F=90=E5=8D=87=E7=89=88=E6=9C=AC=E5=8F=B7=EF=BC=9B?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=91=BD=E4=BB=A4=E8=A1=8C=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli/arg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/arg.rs b/src/cli/arg.rs index 1956351..47b7a81 100644 --- a/src/cli/arg.rs +++ b/src/cli/arg.rs @@ -122,6 +122,7 @@ pub enum MainCommand { }, /// 显示配置文件夹位置。 WhereIsConfig, + /// 获取直播信息。 Xddcc { /// 获取特定账号下节课的直播信息,格式为以半角逗号隔开的字符串。 #[arg(short, long)] From ed5e660f396e478175327935177cb1266910793d Mon Sep 17 00:00:00 2001 From: learturely Date: Tue, 7 May 2024 21:53:54 +0800 Subject: [PATCH 08/14] clippy fixes. --- src/xddcc/live.rs | 11 +++++------ src/xddcc/mod.rs | 11 +++++------ src/xddcc/protocol.rs | 16 ++++++++-------- src/xddcc/room.rs | 27 +++++++++++++-------------- src/xddcc/tools.rs | 17 ++++++++--------- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/xddcc/live.rs b/src/xddcc/live.rs index 8319833..d818ddc 100644 --- a/src/xddcc/live.rs +++ b/src/xddcc/live.rs @@ -29,7 +29,7 @@ impl Live { week: i64, term_year: i32, term: i32, - ) -> Result, ureq::Error> { + ) -> Result, Box> { let vec = crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? .into_json::>() @@ -47,7 +47,7 @@ impl Live { week: i64, week_day: u32, jie: i32, - ) -> Result, ureq::Error> { + ) -> Result, Box> { let vec = crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? .into_json::>() @@ -56,7 +56,7 @@ impl Live { .into_iter() .filter(|live| (live.get_week_day() == week_day) && (live.get_jie() >= jie)); let mut vec = iter.collect::>(); - vec.sort_by(|l1, l2| l1.get_jie().cmp(&l2.get_jie())); + vec.sort_by_key(|live| live.get_jie()); Ok(vec.first().cloned()) } pub fn get_lives_now<'a, Iter: Iterator + Clone>( @@ -81,7 +81,7 @@ impl Live { pb.set_style(sty); for session in sessions.clone() { if first { - (term_year, term, week) = crate::xddcc::tools::term_year_detial(session); + (term_year, term, week) = crate::xddcc::tools::term_year_detail(session); first = false; } let jie = crate::xddcc::tools::now_to_jie(this); @@ -105,7 +105,7 @@ impl Live { let pb = multi.add(indicatif::ProgressBar::new(lives.len() as u64 * 2)); pb.set_style(sty); pb.inc(0); - for session in sessions.clone() { + if let Some(session) = sessions.clone().into_iter().next() { for live in lives { if let Some(room) = Room::get_rooms(session, &live).unwrap() { pb.inc(1); @@ -116,7 +116,6 @@ impl Live { pb.inc(2); } } - break; } pb.finish_with_message("已获取直播地址。"); multi.remove(&pb); diff --git a/src/xddcc/mod.rs b/src/xddcc/mod.rs index 9a3d583..b2cc166 100644 --- a/src/xddcc/mod.rs +++ b/src/xddcc/mod.rs @@ -7,8 +7,8 @@ use crate::xddcc::{live::Live, room::Room, tools::PairVec}; use clap::Parser; use cxsign::store::tables::AccountTable; use indicatif::MultiProgress; -use std::path::PathBuf; use log::warn; +use std::path::PathBuf; #[derive(Parser, Debug)] #[command(author, version, about = "获取直播信息。")] @@ -56,7 +56,7 @@ pub fn xddcc( } else { table.get_sessions() }; - if sessions.len() == 0 { + if sessions.is_empty() { warn!("请至少登录一个账号!"); } let rooms = tools::map_sort_by_key(Room::get_all_rooms(sessions.values(), multi)); @@ -69,15 +69,14 @@ pub fn xddcc( warn!("多余的参数: `-t, --this`.") } let sessions = table.get_sessions(); - if sessions.len() == 0 { + if sessions.is_empty() { warn!("未有登录的账号!"); } - for session in sessions.values() { + if let Some(session) = sessions.values().next() { tools::out( &tools::get_live_video_path(session, &device_code), output.clone(), ); - break; } } else { let sessions = if let Some(accounts) = accounts { @@ -85,7 +84,7 @@ pub fn xddcc( } else { table.get_sessions() }; - if sessions.len() == 0 { + if sessions.is_empty() { warn!("未有登录的账号!"); } tools::out( diff --git a/src/xddcc/protocol.rs b/src/xddcc/protocol.rs index f451287..e815fcf 100644 --- a/src/xddcc/protocol.rs +++ b/src/xddcc/protocol.rs @@ -8,26 +8,26 @@ pub fn list_student_course_live_page( week: i64, term_year: i32, term: i32, -) -> Result { +) -> Result> { let url = format!( "{LIST_STUDENT_COURSE_LIVE_PAGE}?fid=16820&userId={}&week={week}&termYear={term_year}&termId={term}&type=1", session.get_uid(), ); - session.get(&url).call() + Ok(session.get(&url).call()?) } static LIST_SINGLE_COURSE: &str = "http://newesxidian.chaoxing.com/live/listSignleCourse"; -pub fn list_single_course(session: &Session, live_id: &str) -> Result { +pub fn list_single_course(session: &Session, live_id: &str) -> Result> { let url = format!( "{LIST_SINGLE_COURSE}?fid=16820&liveId={live_id}&uId={}", session.get_uid() ); - session.get(&url).call() + Ok(session.get(&url).call()?) } static GET_VIEW_URL: &str = "http://newesxidian.chaoxing.com/live/getViewUrlNoCourseLive"; -pub fn get_live_url(agent: &Agent, device_conde: &str) -> Result { +pub fn get_live_url(agent: &Agent, device_conde: &str) -> Result> { let url = format!("{GET_VIEW_URL}?deviceCode={device_conde}&status=1&fid=16820"); - agent.get(&url).call() + Ok(agent.get(&url).call()?) } // pub fn get_recording_url( // agent: &Agent, @@ -43,7 +43,7 @@ pub fn get_week_detail( agent: &Agent, week: i32, semester_id: i32, -) -> Result { +) -> Result> { let url = format!("{GET_WEEK_DETAIL}?week={week}&semesterId={semester_id}"); - agent.get(&url).call() + Ok(agent.get(&url).call()?) } diff --git a/src/xddcc/room.rs b/src/xddcc/room.rs index d074d8c..6258191 100644 --- a/src/xddcc/room.rs +++ b/src/xddcc/room.rs @@ -22,7 +22,8 @@ pub struct Room { } impl Room { fn trim(mut self) -> Self { - self.name = self.name.trim().to_owned(); + let name = self.name.trim().to_string(); + let _ = std::mem::replace(&mut self.name, name); self } pub fn get_live_video_path(&self, session: &Session) -> VideoPath { @@ -34,7 +35,7 @@ impl Room { // pub fn get_live_url(&self, session: &Session) -> WebUrl { // crate::tools::get_live_web_url(session, &self.device_code) // } - pub fn get_rooms(session: &Session, live_id: &str) -> Result, ureq::Error> { + pub fn get_rooms(session: &Session, live_id: &str) -> Result, Box> { let rooms: Vec = crate::xddcc::protocol::list_single_course(session, live_id)? .into_json() .unwrap(); @@ -44,20 +45,23 @@ impl Room { .map(|r| r.trim())) } pub fn get_all_rooms<'a, Iter: Iterator + Clone>( - sessions: Iter, + mut sessions: Iter, multi: &MultiProgress, ) -> HashMap { let map = Arc::new(Mutex::new(HashMap::new())); - Room::get_all_live_id(&sessions.clone().collect(), Arc::clone(&map), multi); + Room::get_all_live_id( + &sessions.clone().collect::>(), + Arc::clone(&map), + multi, + ); let rooms = Arc::new(Mutex::new(HashMap::new())); - for session in sessions { + if let Some(session) = sessions.next() { Room::id_to_rooms(map.clone(), (*session).clone(), rooms.clone(), multi); - break; } Arc::into_inner(rooms).unwrap().into_inner().unwrap() } pub fn get_all_live_id( - sessions: &Vec<&Session>, + sessions: &[&Session], id_map: Arc>>, multi: &MultiProgress, ) { @@ -73,7 +77,7 @@ impl Room { pb.set_style(sty); let pb = Arc::new(Mutex::new(pb)); let mut handles = Vec::new(); - for session in sessions.into_iter() { + for session in sessions.iter() { let week_thread = week_total / (thread_count - 1) + 1; let thread_count = week_total / week_thread + 1; let week_rest = week_total % week_thread; @@ -112,12 +116,7 @@ impl Room { rooms: Arc>>, multi: &MultiProgress, ) { - let ids = id_map - .lock() - .unwrap() - .values() - .map(|a| *a) - .collect::>(); + let ids = id_map.lock().unwrap().values().copied().collect::>(); let len = ids.len() as i32; let total = len; let sty = indicatif::ProgressStyle::with_template( diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs index f405d44..b2028ed 100644 --- a/src/xddcc/tools.rs +++ b/src/xddcc/tools.rs @@ -54,7 +54,7 @@ fn web_url_to_video_path(url: &WebUrl) -> VideoPath { } } fn get_live_web_url(session: &Session, device_code: &str) -> WebUrl { - let url = crate::xddcc::protocol::get_live_url(&session, &device_code) + let url = crate::xddcc::protocol::get_live_url(session, device_code) .unwrap() .into_string() .unwrap(); @@ -121,8 +121,8 @@ pub fn map_sort_by_key(map: HashMap) -> Vec<(K, V)> { map.sort_by(|x, y| x.0.cmp(&y.0)); map.into_iter().collect() } -pub fn term_year_detial(session: &Session) -> (i32, i32, i64) { - let data_time = chrono::DateTime::::from(std::time::SystemTime::now()); +pub fn term_year_detail(session: &Session) -> (i32, i32, i64) { + let data_time = chrono::DateTime::::from(std::time::SystemTime::now()); let year = chrono::Datelike::year(&data_time); let semester_id = year_to_semester_id(year - 1, 2); @@ -130,11 +130,10 @@ pub fn term_year_detial(session: &Session) -> (i32, i32, i64) { struct WeekDetail { date1: String, } - let WeekDetail { date1, .. } = - crate::xddcc::protocol::get_week_detail(&session, 1, semester_id) - .unwrap() - .into_json() - .unwrap(); + let WeekDetail { date1, .. } = crate::xddcc::protocol::get_week_detail(session, 1, semester_id) + .unwrap() + .into_json() + .unwrap(); let date = date1.split('-').map(|s| s.trim()).collect::>(); let month = date[0].parse::().unwrap(); let day = date[1].parse::().unwrap(); @@ -143,7 +142,7 @@ pub fn term_year_detial(session: &Session) -> (i32, i32, i64) { ) .unwrap(); let week = data_time - .signed_duration_since(&term_begin_data_time) + .signed_duration_since(term_begin_data_time) .num_weeks() + 1; let (term_year, term) = if chrono::Datelike::month(&data_time) * 100 From a69af4e6604c143603044587cc66d2b4a2053197 Mon Sep 17 00:00:00 2001 From: worksoup <2055038075@qq.com> Date: Fri, 10 May 2024 16:02:29 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cxsign.svg | 229 ----------------------------------------------------- xddcc.svg | 163 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 229 deletions(-) delete mode 100755 cxsign.svg create mode 100755 xddcc.svg diff --git a/cxsign.svg b/cxsign.svg deleted file mode 100755 index c468c7b..0000000 --- a/cxsign.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - diff --git a/xddcc.svg b/xddcc.svg new file mode 100755 index 0000000..aacc8fc --- /dev/null +++ b/xddcc.svg @@ -0,0 +1,163 @@ + + + + From c1617520e934d20ff4d8444b9a6e67cb76ed8fc7 Mon Sep 17 00:00:00 2001 From: learturely Date: Fri, 10 May 2024 19:19:43 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/xddcc/live.rs | 50 ++++++++++++++++++++++++++++++---------------- src/xddcc/mod.rs | 10 ++++++---- src/xddcc/room.rs | 22 ++++++++++++++------ src/xddcc/tools.rs | 49 +++++++++++++++++++++++++++++++++------------ 4 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/xddcc/live.rs b/src/xddcc/live.rs index d818ddc..ffb38ef 100644 --- a/src/xddcc/live.rs +++ b/src/xddcc/live.rs @@ -1,11 +1,12 @@ use std::collections::{HashMap, HashSet}; +use crate::xddcc::tools::{json_parsing_error_handler, prog_init_error_handler}; +use crate::xddcc::{room::Room, tools::VideoPath}; use cxsign::Session; use indicatif::MultiProgress; +use log::warn; use serde::{Deserialize, Serialize}; -use crate::xddcc::{room::Room, tools::VideoPath}; - #[derive(Deserialize, Serialize, Clone, Debug)] pub struct Live { place: String, @@ -33,7 +34,7 @@ impl Live { let vec = crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? .into_json::>() - .unwrap(); + .unwrap_or_else(json_parsing_error_handler); let mut map = HashMap::new(); for i in vec { map.insert(i.place, i.id); @@ -51,7 +52,7 @@ impl Live { let vec = crate::xddcc::protocol::list_student_course_live_page(session, week, term_year, term)? .into_json::>() - .unwrap(); + .unwrap_or_else(json_parsing_error_handler); let iter = vec .into_iter() .filter(|live| (live.get_week_day() == week_day) && (live.get_jie() >= jie)); @@ -76,7 +77,7 @@ impl Live { let sty = indicatif::ProgressStyle::with_template( "获取直播号:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", ) - .unwrap(); + .unwrap_or_else(prog_init_error_handler); let pb = multi.add(indicatif::ProgressBar::new(total)); pb.set_style(sty); for session in sessions.clone() { @@ -101,19 +102,27 @@ impl Live { let sty = indicatif::ProgressStyle::with_template( "获取地址中:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", ) - .unwrap(); + .unwrap_or_else(prog_init_error_handler); let pb = multi.add(indicatif::ProgressBar::new(lives.len() as u64 * 2)); pb.set_style(sty); pb.inc(0); if let Some(session) = sessions.clone().into_iter().next() { for live in lives { - if let Some(room) = Room::get_rooms(session, &live).unwrap() { - pb.inc(1); - let video_path = room.get_live_video_path(session); - pb.inc(1); - rooms.insert(live, (room, video_path)); - } else { - pb.inc(2); + match Room::get_rooms(session, &live) { + Ok(room) => { + if let Some(room) = room { + pb.inc(1); + let video_path = room.get_live_video_path(session); + pb.inc(1); + rooms.insert(live, (room, video_path)); + } else { + pb.inc(2); + } + } + Err(e) => { + warn!("教室获取错误:{e}."); + pb.inc(2); + } } } } @@ -122,10 +131,17 @@ impl Live { let mut results = HashMap::new(); for (session, live) in lives_map { if let Some((room, video_path)) = rooms.get(&live.get_id()) { - results.insert( - session.get_uid(), - (session.get_stu_name(), room.clone(), video_path.clone()), - ); + match video_path { + Ok(video_path) => { + results.insert( + session.get_uid(), + (session.get_stu_name(), room.clone(), video_path.clone()), + ); + } + Err(e) => { + warn!("获取教室失败:{e}.") + } + } } } results diff --git a/src/xddcc/mod.rs b/src/xddcc/mod.rs index b2cc166..bfb06f7 100644 --- a/src/xddcc/mod.rs +++ b/src/xddcc/mod.rs @@ -73,10 +73,12 @@ pub fn xddcc( warn!("未有登录的账号!"); } if let Some(session) = sessions.values().next() { - tools::out( - &tools::get_live_video_path(session, &device_code), - output.clone(), - ); + tools::get_live_video_path(session, &device_code) + .ok() + .map(|path| { + tools::out(&path, output.clone()); + true + }); } } else { let sessions = if let Some(accounts) = accounts { diff --git a/src/xddcc/room.rs b/src/xddcc/room.rs index 6258191..4a2d48c 100644 --- a/src/xddcc/room.rs +++ b/src/xddcc/room.rs @@ -8,6 +8,10 @@ use cxsign::Session; use indicatif::MultiProgress; use serde::{Deserialize, Serialize}; +use crate::xddcc::tools::{ + arc_into_inner_error_handler, json_parsing_error_handler, mutex_into_inner_error_handler, + prog_init_error_handler, +}; use crate::xddcc::{live::Live, tools::VideoPath}; #[derive(Deserialize, Serialize, Debug, Clone)] @@ -26,7 +30,7 @@ impl Room { let _ = std::mem::replace(&mut self.name, name); self } - pub fn get_live_video_path(&self, session: &Session) -> VideoPath { + pub fn get_live_video_path(&self, session: &Session) -> Result> { crate::xddcc::tools::get_live_video_path(session, &self.device_code) } // pub fn get_live_video_path(&self, session: &Session) -> VideoPath { @@ -38,7 +42,7 @@ impl Room { pub fn get_rooms(session: &Session, live_id: &str) -> Result, Box> { let rooms: Vec = crate::xddcc::protocol::list_single_course(session, live_id)? .into_json() - .unwrap(); + .unwrap_or_else(json_parsing_error_handler); Ok(rooms .into_iter() .find(|r| r.id.to_string() == live_id) @@ -58,7 +62,10 @@ impl Room { if let Some(session) = sessions.next() { Room::id_to_rooms(map.clone(), (*session).clone(), rooms.clone(), multi); } - Arc::into_inner(rooms).unwrap().into_inner().unwrap() + Arc::into_inner(rooms) + .unwrap_or_else(arc_into_inner_error_handler) + .into_inner() + .unwrap_or_else(mutex_into_inner_error_handler) } pub fn get_all_live_id( sessions: &[&Session], @@ -72,7 +79,7 @@ impl Room { let sty = indicatif::ProgressStyle::with_template( "获取直播号:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", ) - .unwrap(); + .unwrap_or_else(prog_init_error_handler); let pb = multi.add(indicatif::ProgressBar::new(total as u64)); pb.set_style(sty); let pb = Arc::new(Mutex::new(pb)); @@ -93,7 +100,7 @@ impl Room { } { let (year, term, week) = crate::xddcc::tools::date_count_to_year_term_week(now_year, date_count); - let lives = Live::get_lives(&session, week, year, term).unwrap(); + let lives = Live::get_lives(&session, week, year, term).unwrap_or_default(); for live in lives { id_map.lock().unwrap().insert(live.0, live.1); } @@ -106,7 +113,10 @@ impl Room { for handle in handles { handle.join().unwrap(); } - let pb = Arc::into_inner(pb).unwrap().into_inner().unwrap(); + let pb = Arc::into_inner(pb) + .unwrap_or_else(arc_into_inner_error_handler) + .into_inner() + .unwrap_or_else(mutex_into_inner_error_handler); pb.finish_with_message("获取直播号完成。"); multi.remove(&pb); } diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs index b2028ed..68e7868 100644 --- a/src/xddcc/tools.rs +++ b/src/xddcc/tools.rs @@ -1,9 +1,30 @@ use chrono::{Local, Timelike}; use cxsign::Session; -use log::info; +use log::{error, info}; use serde::{Deserialize, Serialize}; +use std::error::Error as ErrorTrait; use std::{collections::HashMap, hash::Hash}; +pub(crate) fn json_parsing_error_handler(e: impl ErrorTrait) -> T { + error!("json 解析出错!错误信息:{e}."); + panic!() +} +pub(crate) fn resp_parsing_error_handler(e: impl ErrorTrait) -> T { + error!("响应数据无法转为字符串,错误信息:{e}."); + panic!() +} +pub(crate) fn prog_init_error_handler(e: impl ErrorTrait) -> T { + error!("json 解析出错!错误信息:{e}."); + panic!() +} +pub(crate) fn arc_into_inner_error_handler() -> T { + error!("Arc 指针为空!"); + panic!() +} +pub(crate) fn mutex_into_inner_error_handler(e: impl ErrorTrait) -> T { + error!("保有互斥锁的其他线程发生 panic, 错误信息:{e}."); + panic!() +} #[derive(Serialize, Default, Debug, Clone)] pub struct VideoPath { ppt_video: Option, @@ -19,7 +40,7 @@ fn web_url_to_video_path(url: &WebUrl) -> VideoPath { let url = &url.url.split("?info=").collect::>()[1]; let url = percent_encoding::percent_decode_str(url) .decode_utf8() - .unwrap() + .unwrap_or_default() .to_string(); #[derive(Deserialize)] struct VideoPathInternal { @@ -45,7 +66,7 @@ fn web_url_to_video_path(url: &WebUrl) -> VideoPath { teacher_track, student_full, }, - } = ureq::serde_json::from_str(&url).unwrap(); + } = serde_json::from_str(&url).unwrap_or_else(json_parsing_error_handler); VideoPath { ppt_video, teacher_full, @@ -53,16 +74,18 @@ fn web_url_to_video_path(url: &WebUrl) -> VideoPath { student_full, } } -fn get_live_web_url(session: &Session, device_code: &str) -> WebUrl { - let url = crate::xddcc::protocol::get_live_url(session, device_code) - .unwrap() +fn get_live_web_url(session: &Session, device_code: &str) -> Result> { + let url = crate::xddcc::protocol::get_live_url(session, device_code)? .into_string() - .unwrap(); - WebUrl { url } + .unwrap_or_else(resp_parsing_error_handler); + Ok(WebUrl { url }) } -pub fn get_live_video_path(session: &Session, device_code: &str) -> VideoPath { +pub fn get_live_video_path( + session: &Session, + device_code: &str, +) -> Result> { let url = get_live_web_url(session, device_code); - web_url_to_video_path(&url) + Ok(web_url_to_video_path(&url?)) } pub fn year_to_semester_id(year: i32, term: i32) -> i32 { let mut r = 2 * year - 4035 + term; @@ -137,9 +160,9 @@ pub fn term_year_detail(session: &Session) -> (i32, i32, i64) { let date = date1.split('-').map(|s| s.trim()).collect::>(); let month = date[0].parse::().unwrap(); let day = date[1].parse::().unwrap(); - let term_begin_data_time = as std::str::FromStr>::from_str( - &format!("{year}-{month}-{day}T00:00:00.0+08:00"), - ) + let term_begin_data_time = as std::str::FromStr>::from_str(&format!( + "{year}-{month}-{day}T00:00:00.0+08:00" + )) .unwrap(); let week = data_time .signed_duration_since(term_begin_data_time) From 56ad35fc4e7e228f69eb75fcb530f07b60cb2583 Mon Sep 17 00:00:00 2001 From: learturely Date: Sun, 12 May 2024 18:39:07 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E6=93=8D=E4=BD=9C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/xddcc/tools.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs index 68e7868..4e8e7aa 100644 --- a/src/xddcc/tools.rs +++ b/src/xddcc/tools.rs @@ -206,6 +206,6 @@ pub fn out(contents: &S, path: Option) { if let Some(path) = path { std::fs::write(path, contents).expect("写入内容出错!"); } else { - info!("{contents}") + println!("{contents}") } } From 2ac29ddcb65ed1f43e42dcb0472c157bbd7db275 Mon Sep 17 00:00:00 2001 From: learturely Date: Tue, 14 May 2024 16:28:49 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E6=93=8D=E4=BD=9C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/xddcc/tools.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs index 4e8e7aa..21aaa75 100644 --- a/src/xddcc/tools.rs +++ b/src/xddcc/tools.rs @@ -1,6 +1,6 @@ use chrono::{Local, Timelike}; use cxsign::Session; -use log::{error, info}; +use log::error; use serde::{Deserialize, Serialize}; use std::error::Error as ErrorTrait; use std::{collections::HashMap, hash::Hash}; From ac27fdfb737b39a3d0585b4f40505312b7b48fb5 Mon Sep 17 00:00:00 2001 From: learturely Date: Thu, 20 Jun 2024 00:19:40 +0800 Subject: [PATCH 13/14] =?UTF-8?q?[XDDCC]:=20=E5=88=97=E5=87=BA=E5=9B=9E?= =?UTF-8?q?=E6=94=BE=E5=9C=B0=E5=9D=80=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli/arg.rs | 3 +++ src/xddcc/live.rs | 8 ++++---- src/xddcc/protocol.rs | 7 ++++++- src/xddcc/room.rs | 36 ++++++++++++++++++++++++++++++++---- src/xddcc/tools.rs | 13 +++++++++++++ 5 files changed, 58 insertions(+), 9 deletions(-) mode change 100644 => 100755 src/cli/arg.rs mode change 100644 => 100755 src/xddcc/live.rs mode change 100644 => 100755 src/xddcc/protocol.rs mode change 100644 => 100755 src/xddcc/room.rs mode change 100644 => 100755 src/xddcc/tools.rs diff --git a/src/cli/arg.rs b/src/cli/arg.rs old mode 100644 new mode 100755 index 47b7a81..fb61043 --- a/src/cli/arg.rs +++ b/src/cli/arg.rs @@ -133,6 +133,9 @@ pub enum MainCommand { /// 通过 `device_code` 获取直播信息。 #[arg(short, long)] device_code: Option, + /// 获取某节课的回放信息,格式为`周数/节数`。 + #[arg(short, long)] + id: Option, /// 导出文件路径。可选提供。 #[arg(short, long)] output: Option, diff --git a/src/xddcc/live.rs b/src/xddcc/live.rs old mode 100644 new mode 100755 index ffb38ef..0e69915 --- a/src/xddcc/live.rs +++ b/src/xddcc/live.rs @@ -16,13 +16,13 @@ pub struct Live { jie: i32, } impl Live { - pub fn get_id(&self) -> String { - self.id.to_string() + pub fn get_id(&self) -> i64 { + self.id } pub fn get_week_day(&self) -> u32 { self.week_day } - fn get_jie(&self) -> i32 { + pub fn get_jie(&self) -> i32 { self.jie } pub fn get_lives( @@ -108,7 +108,7 @@ impl Live { pb.inc(0); if let Some(session) = sessions.clone().into_iter().next() { for live in lives { - match Room::get_rooms(session, &live) { + match Room::get_rooms(session, live) { Ok(room) => { if let Some(room) = room { pb.inc(1); diff --git a/src/xddcc/protocol.rs b/src/xddcc/protocol.rs old mode 100644 new mode 100755 index e815fcf..8078fae --- a/src/xddcc/protocol.rs +++ b/src/xddcc/protocol.rs @@ -1,6 +1,11 @@ use cxsign::Session; use ureq::{Agent, Response}; +static GET_VIEW_URL_HLS: &str = "http://newesxidian.chaoxing.com/live/getViewUrlHls"; +pub fn get_view_url_hls(agent: &Agent, live_id: i64) -> Result> { + let url = format!("{GET_VIEW_URL_HLS}?liveId={live_id}&status=1&jie=&isStudent="); + Ok(agent.get(&url).call()?) +} static LIST_STUDENT_COURSE_LIVE_PAGE: &str = "http://newesxidian.chaoxing.com/frontLive/listStudentCourseLivePage"; pub fn list_student_course_live_page( @@ -16,7 +21,7 @@ pub fn list_student_course_live_page( Ok(session.get(&url).call()?) } static LIST_SINGLE_COURSE: &str = "http://newesxidian.chaoxing.com/live/listSignleCourse"; -pub fn list_single_course(session: &Session, live_id: &str) -> Result> { +pub fn list_single_course(session: &Session, live_id: i64) -> Result> { let url = format!( "{LIST_SINGLE_COURSE}?fid=16820&liveId={live_id}&uId={}", session.get_uid() diff --git a/src/xddcc/room.rs b/src/xddcc/room.rs old mode 100644 new mode 100755 index 4a2d48c..414645b --- a/src/xddcc/room.rs +++ b/src/xddcc/room.rs @@ -22,7 +22,7 @@ pub struct Room { device_code: String, #[serde(rename = "schoolRoomId")] room_id: i32, - id: i32, + id: i64, } impl Room { fn trim(mut self) -> Self { @@ -33,19 +33,22 @@ impl Room { pub fn get_live_video_path(&self, session: &Session) -> Result> { crate::xddcc::tools::get_live_video_path(session, &self.device_code) } + pub fn get_recording_url(&self, session: &Session) -> Result> { + crate::xddcc::tools::get_recording_live_video_path(session, self.id) + } // pub fn get_live_video_path(&self, session: &Session) -> VideoPath { // crate::tools::get_live_video_path(session, &self.device_code) // } // pub fn get_live_url(&self, session: &Session) -> WebUrl { // crate::tools::get_live_web_url(session, &self.device_code) // } - pub fn get_rooms(session: &Session, live_id: &str) -> Result, Box> { + pub fn get_rooms(session: &Session, live_id: i64) -> Result, Box> { let rooms: Vec = crate::xddcc::protocol::list_single_course(session, live_id)? .into_json() .unwrap_or_else(json_parsing_error_handler); Ok(rooms .into_iter() - .find(|r| r.id.to_string() == live_id) + .find(|r| r.id == live_id) .map(|r| r.trim())) } pub fn get_all_rooms<'a, Iter: Iterator + Clone>( @@ -67,6 +70,31 @@ impl Room { .into_inner() .unwrap_or_else(mutex_into_inner_error_handler) } + pub fn get_recording_lives( + session: &Session, + live_id: i64, + multi: &MultiProgress, + ) -> Result, Box> { + let rooms: Vec = crate::xddcc::protocol::list_single_course(&session, live_id)? + .into_json() + .unwrap_or_else(json_parsing_error_handler); + let total = rooms.len(); + let sty = indicatif::ProgressStyle::with_template( + "获取回放地址:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap_or_else(prog_init_error_handler); + let pb = multi.add(indicatif::ProgressBar::new(total as u64)); + pb.set_style(sty); + let pathes = rooms.into_iter().filter_map(|room| { + let path = room.get_live_video_path(session).ok().map(|p| (room.id, p)); + pb.inc(1); + path + }); + let pathes = pathes.collect(); + pb.finish_with_message("获取回放地址完成。"); + multi.remove(&pb); + Ok(pathes) + } pub fn get_all_live_id( sessions: &[&Session], id_map: Arc>>, @@ -152,7 +180,7 @@ impl Room { let rooms = rooms.clone(); let pb = Arc::clone(&pb); let handle = std::thread::spawn(move || { - let room = Room::get_rooms(&session, id.to_string().as_str()).unwrap(); + let room = Room::get_rooms(&session, id).unwrap(); if let Some(room) = room { rooms.lock().unwrap().insert(room.name, room.device_code); } diff --git a/src/xddcc/tools.rs b/src/xddcc/tools.rs old mode 100644 new mode 100755 index 21aaa75..06f9ec4 --- a/src/xddcc/tools.rs +++ b/src/xddcc/tools.rs @@ -80,6 +80,12 @@ fn get_live_web_url(session: &Session, device_code: &str) -> Result Result> { + let url = crate::xddcc::protocol::get_view_url_hls(session, live_id)? + .into_string() + .unwrap_or_else(resp_parsing_error_handler); + Ok(WebUrl { url }) +} pub fn get_live_video_path( session: &Session, device_code: &str, @@ -87,6 +93,13 @@ pub fn get_live_video_path( let url = get_live_web_url(session, device_code); Ok(web_url_to_video_path(&url?)) } +pub fn get_recording_live_video_path( + session: &Session, + live_id: i64, +) -> Result> { + let url = get_recording_live_web_url(session, live_id); + Ok(web_url_to_video_path(&url?)) +} pub fn year_to_semester_id(year: i32, term: i32) -> i32 { let mut r = 2 * year - 4035 + term; if year == 2018 { From 343591e127a03d1e12a5a9eabf3eaccd45d8cfaa Mon Sep 17 00:00:00 2001 From: learturely Date: Thu, 20 Jun 2024 01:58:20 +0800 Subject: [PATCH 14/14] =?UTF-8?q?[XDDCC]:=20fix=20=E5=88=97=E5=87=BA?= =?UTF-8?q?=E5=9B=9E=E6=94=BE=E5=9C=B0=E5=9D=80=E4=BD=86=E5=85=B6=E5=AE=9E?= =?UTF-8?q?=E6=98=AF=E7=9B=B4=E6=92=AD=E5=9C=B0=E5=9D=80=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E3=80=82=20=E6=B7=BB=E5=8A=A0=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E5=87=A0=E4=B8=AA=E9=80=89=E9=A1=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli/arg.rs | 11 +++-- src/xddcc/lesson.rs | 107 ++++++++++++++++++++++++++++++++++++++++++ src/xddcc/protocol.rs | 2 +- src/xddcc/room.rs | 29 +----------- 4 files changed, 116 insertions(+), 33 deletions(-) create mode 100644 src/xddcc/lesson.rs diff --git a/src/cli/arg.rs b/src/cli/arg.rs index fb61043..9dd8ef9 100755 --- a/src/cli/arg.rs +++ b/src/cli/arg.rs @@ -127,21 +127,24 @@ pub enum MainCommand { /// 获取特定账号下节课的直播信息,格式为以半角逗号隔开的字符串。 #[arg(short, long)] accounts: Option, - /// 覆盖默认行为至获取当前课的直播信息。 - #[arg(short, long)] - this: bool, /// 通过 `device_code` 获取直播信息。 #[arg(short, long)] device_code: Option, - /// 获取某节课的回放信息,格式为`周数/节数`。 + /// 获取回放信息,参数为 `live_id`, 默认获取整门课的。 #[arg(short, long)] id: Option, + /// 获取某门课中每节课的 `live_id`. + #[arg(short, long)] + just_id: bool, /// 导出文件路径。可选提供。 #[arg(short, long)] output: Option, /// 列出所有设备码。 #[arg(short, long)] list: bool, + /// 获取直播信息时覆盖默认行为至获取当前课的直播信息,获取回放信息时指定只获取一节课的回放信息。 + #[arg(short, long)] + this: bool, // /// 网页播放器地址。 // #[arg(short, long)] // web: bool, diff --git a/src/xddcc/lesson.rs b/src/xddcc/lesson.rs new file mode 100644 index 0000000..ca139fc --- /dev/null +++ b/src/xddcc/lesson.rs @@ -0,0 +1,107 @@ +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +use cxsign::user::Session; +use indicatif::MultiProgress; +use serde::{Deserialize, Serialize}; + +use super::tools::{ + arc_into_inner_error_handler, json_parsing_error_handler, mutex_into_inner_error_handler, + prog_init_error_handler, VideoPath, +}; + +#[derive(Deserialize, Serialize, Clone, Debug)] +struct Time_ { + time: i64, +} +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct Lesson { + #[serde(rename = "startTime")] + start_time: Time_, + id: i64, +} + +impl Lesson { + pub fn get_start_time(&self) -> i64 { + self.start_time.time + } + pub fn get_live_id(&self) -> i64 { + self.id + } + pub fn get_recording_url( + session: &Session, + live_id: i64, + ) -> Result> { + crate::xddcc::tools::get_recording_live_video_path(session, live_id) + } + pub fn get_all_lessons(session: &Session, live_id: i64) -> Result, Box> { + let mut lessons: Vec = + crate::xddcc::protocol::list_single_course(&session, live_id)? + .into_json() + .unwrap_or_else(json_parsing_error_handler); + lessons.sort_by_key(|l| l.get_start_time()); + Ok(lessons.into_iter().map(|l| l.get_live_id()).collect()) + } + pub fn get_recording_lives( + session: &Session, + live_id: i64, + multi: &MultiProgress, + ) -> Result, Box> { + let lessons: Vec = crate::xddcc::protocol::list_single_course(&session, live_id)? + .into_json() + .unwrap_or_else(json_parsing_error_handler); + let total = lessons.len(); + let thread_count = total / 64; + let rest_count = total % 64; + let sty = indicatif::ProgressStyle::with_template( + "获取回放地址:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap_or_else(prog_init_error_handler); + let pb = multi.add(indicatif::ProgressBar::new(total as u64)); + pb.set_style(sty); + let pb = Arc::new(Mutex::new(pb)); + let pathes = Arc::new(Mutex::new(HashMap::new())); + let mut handles = Vec::new(); + for block in 0..64 { + let ref_ = if block < rest_count { + ((thread_count + 1) * block)..((thread_count + 1) * (block + 1)) + } else { + (thread_count * block + rest_count)..(thread_count * (block + 1) + rest_count) + }; + let session = (*session).clone(); + let pathes = Arc::clone(&pathes); + let pb = Arc::clone(&pb); + let mut lessons_ = vec![]; + for lesson in &lessons[ref_] { + lessons_.push(lesson.clone()) + } + let handle = std::thread::spawn(move || { + for lesson in lessons_ { + if let Some(path) = + Lesson::get_recording_url(&session, lesson.get_live_id()).ok() + { + pathes.lock().unwrap().insert(lesson.get_start_time(), path); + } + pb.lock().unwrap().inc(1); + } + }); + handles.push(handle); + } + for handle in handles { + handle.join().unwrap(); + } + let pathes = Arc::into_inner(pathes) + .unwrap_or_else(arc_into_inner_error_handler) + .into_inner() + .unwrap_or_else(mutex_into_inner_error_handler); + let pb = Arc::into_inner(pb) + .unwrap_or_else(arc_into_inner_error_handler) + .into_inner() + .unwrap_or_else(mutex_into_inner_error_handler); + pb.finish_with_message("获取回放地址完成。"); + multi.remove(&pb); + Ok(pathes) + } +} diff --git a/src/xddcc/protocol.rs b/src/xddcc/protocol.rs index 8078fae..60f654a 100755 --- a/src/xddcc/protocol.rs +++ b/src/xddcc/protocol.rs @@ -3,7 +3,7 @@ use ureq::{Agent, Response}; static GET_VIEW_URL_HLS: &str = "http://newesxidian.chaoxing.com/live/getViewUrlHls"; pub fn get_view_url_hls(agent: &Agent, live_id: i64) -> Result> { - let url = format!("{GET_VIEW_URL_HLS}?liveId={live_id}&status=1&jie=&isStudent="); + let url = format!("{GET_VIEW_URL_HLS}?liveId={live_id}&status=2&jie=&isStudent="); Ok(agent.get(&url).call()?) } static LIST_STUDENT_COURSE_LIVE_PAGE: &str = diff --git a/src/xddcc/room.rs b/src/xddcc/room.rs index 414645b..7ac3542 100755 --- a/src/xddcc/room.rs +++ b/src/xddcc/room.rs @@ -33,9 +33,7 @@ impl Room { pub fn get_live_video_path(&self, session: &Session) -> Result> { crate::xddcc::tools::get_live_video_path(session, &self.device_code) } - pub fn get_recording_url(&self, session: &Session) -> Result> { - crate::xddcc::tools::get_recording_live_video_path(session, self.id) - } + // pub fn get_live_video_path(&self, session: &Session) -> VideoPath { // crate::tools::get_live_video_path(session, &self.device_code) // } @@ -70,31 +68,6 @@ impl Room { .into_inner() .unwrap_or_else(mutex_into_inner_error_handler) } - pub fn get_recording_lives( - session: &Session, - live_id: i64, - multi: &MultiProgress, - ) -> Result, Box> { - let rooms: Vec = crate::xddcc::protocol::list_single_course(&session, live_id)? - .into_json() - .unwrap_or_else(json_parsing_error_handler); - let total = rooms.len(); - let sty = indicatif::ProgressStyle::with_template( - "获取回放地址:[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", - ) - .unwrap_or_else(prog_init_error_handler); - let pb = multi.add(indicatif::ProgressBar::new(total as u64)); - pb.set_style(sty); - let pathes = rooms.into_iter().filter_map(|room| { - let path = room.get_live_video_path(session).ok().map(|p| (room.id, p)); - pb.inc(1); - path - }); - let pathes = pathes.collect(); - pb.finish_with_message("获取回放地址完成。"); - multi.remove(&pb); - Ok(pathes) - } pub fn get_all_live_id( sessions: &[&Session], id_map: Arc>>,