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>>,