From 92ce90163c3d84f0fab99e6dc192a65c616ffd81 Mon Sep 17 00:00:00 2001 From: THMonster Date: Wed, 21 Jun 2023 10:10:52 +0800 Subject: [PATCH] new feature: switch danmaku fps support hdr and hires for b refine title display set h264 as default --- .github/workflows/build.yml | 121 +++++------------ Cargo.lock | 2 +- Cargo.toml | 2 +- src/config/mod.rs | 2 + src/ffmpeg/mod.rs | 20 +-- src/mpv/cmdparser.rs | 5 + src/mpv/mod.rs | 112 ++++++++++++--- src/streamfinder/bilibili.rs | 257 +++++++++-------------------------- src/utils/mod.rs | 4 + 9 files changed, 215 insertions(+), 310 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eba2e88..b594e16 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,8 +4,34 @@ on: push: jobs: - android: - runs-on: ubuntu-20.04 + build: + name: build + runs-on: ${{ matrix.os }} + strategy: + matrix: + build: [aarch64, aarch64-musl, amd64, amd64-musl] + include: + - build: aarch64 + os: ubuntu-latest + rust: stable + cross: true + target: aarch64-unknown-linux-gnu + - build: aarch64-musl + os: ubuntu-latest + rust: stable + cross: true + target: aarch64-unknown-linux-musl + - build: amd64 + os: ubuntu-latest + rust: stable + cross: false + target: x86_64-unknown-linux-gnu + - build: amd64-musl + os: ubuntu-latest + rust: stable + cross: true + target: x86_64-unknown-linux-musl + fail-fast: false steps: - name: Checkout @@ -14,98 +40,19 @@ jobs: submodules: 'recursive' - uses: actions-rs/toolchain@v1 with: - toolchain: stable - target: aarch64-linux-android + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} override: true - uses: actions-rs/cargo@v1 with: - use-cross: true + use-cross: ${{ matrix.cross }} command: build - args: --release --target aarch64-linux-android - - run: mv ./target/aarch64-linux-android/release/dmlive ./dmlive-android - - uses: ncipollo/release-action@v1 - with: - allowUpdates: true - tag: "release" - artifacts: "./dmlive-android" - token: ${{ secrets.GITHUB_TOKEN }} - aarch64: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - run: sudo apt-get install pkg-config libssl-dev p7zip-full - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: aarch64-unknown-linux-gnu - override: true - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --release --target aarch64-unknown-linux-gnu - - run: mv ./target/aarch64-unknown-linux-gnu/release/dmlive ./dmlive-aarch64 - - - uses: ncipollo/release-action@v1 - with: - allowUpdates: true - tag: "release" - artifacts: "./dmlive-aarch64" - token: ${{ secrets.GITHUB_TOKEN }} - amd64: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - run: sudo apt-get install pkg-config libssl-dev p7zip-full - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: x86_64-unknown-linux-gnu - override: true - - uses: actions-rs/cargo@v1 - with: - command: build - args: --release - - run: mv ./target/release/dmlive ./dmlive-amd64 - - - uses: ncipollo/release-action@v1 - with: - allowUpdates: true - tag: "release" - artifacts: "./dmlive-amd64" - token: ${{ secrets.GITHUB_TOKEN }} - windows: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - run: sudo apt-get install pkg-config libssl-dev p7zip-full - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: x86_64-pc-windows-gnu - override: true - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --release --target x86_64-pc-windows-gnu - - run: mv ./target/release/dmlive.exe ./dmlive-win64.exe + args: --release --target ${{ matrix.target }} + - run: mv ./target/release/dmlive ./dmlive-${{ matrix.build }} || mv "./target/${{ matrix.target }}/release/dmlive" ./dmlive-${{ matrix.build }} - uses: ncipollo/release-action@v1 with: allowUpdates: true tag: "release" - artifacts: "./dmlive-win64.exe" + artifacts: "./dmlive-${{ matrix.build }}" token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index c7f822e..2a55e95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -473,7 +473,7 @@ dependencies = [ [[package]] name = "dmlive" -version = "5.2.0" +version = "5.3.0" dependencies = [ "aes", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index b111f44..aeb6b07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dmlive" -version = "5.2.0" +version = "5.3.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/config/mod.rs b/src/config/mod.rs index 47ce796..7541472 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -47,6 +47,7 @@ pub struct ConfigManager { pub font_scale: RwLock, pub font_alpha: RwLock, pub danmaku_speed: RwLock, + pub display_fps: RwLock<(u64, u64)>, pub room_url: String, pub http_address: Option, pub run_mode: RunMode, @@ -125,6 +126,7 @@ impl ConfigManager { on_writing: AtomicBool::new(false), plat, cookies_from_browser: c.cookies_from_browser.unwrap_or_else(|| "".into()), + display_fps: RwLock::new((60, 0)), } } diff --git a/src/ffmpeg/mod.rs b/src/ffmpeg/mod.rs index 5f00bdb..654fac1 100644 --- a/src/ffmpeg/mod.rs +++ b/src/ffmpeg/mod.rs @@ -7,18 +7,12 @@ use tokio::sync::oneshot; use tokio::task::spawn_local; use tokio::time::timeout; use tokio::{ - io::{ - AsyncBufReadExt, - AsyncWriteExt, - }, + io::{AsyncBufReadExt, AsyncWriteExt}, process::Command, sync::RwLock, }; -use crate::{ - config::ConfigManager, - dmlive::DMLMessage, -}; +use crate::{config::ConfigManager, dmlive::DMLMessage}; pub struct FfmpegControl { ipc_manager: Arc, @@ -42,9 +36,17 @@ impl FfmpegControl { async fn run_write_record_task(&self, title: String) -> tokio::task::JoinHandle<()> { let in_stream = self.ipc_manager.get_f2m_socket_path(); + let max_len = match title.char_indices().nth(70) { + Some(it) => it.0, + None => title.len(), + }; spawn_local(async move { let now = chrono::Local::now(); - let filename = format!("{} - {}.mkv", title.replace('/', "-"), now.format("%F %T")); + let filename = format!( + "{} - {}.mkv", + title[..max_len].replace('/', "-"), + now.format("%F %T") + ); loop { let mut cmd = Command::new("ffmpeg"); cmd.args(&["-y", "-xerror", "-hide_banner", "-nostats", "-nostdin"]); diff --git a/src/mpv/cmdparser.rs b/src/mpv/cmdparser.rs index 6b45182..e78118f 100644 --- a/src/mpv/cmdparser.rs +++ b/src/mpv/cmdparser.rs @@ -7,6 +7,7 @@ pub struct CmdParser { pub fsup: bool, pub fsdown: bool, pub nick: bool, + pub fps: bool, pub fs: Option, pub fa: Option, pub speed: Option, @@ -21,6 +22,7 @@ impl CmdParser { let mut fsup = false; let mut fsdown = false; let mut nick = false; + let mut fps = false; let mut fs = None; let mut fa = None; let mut speed = None; @@ -41,6 +43,8 @@ impl CmdParser { fsdown = true; } else if cmd.trim().eq("nick") { nick = true; + } else if cmd.trim().eq("fps") { + fps = true; } let subcmds: Vec<&str> = cmd.split('=').collect(); let mut iter = subcmds.iter(); @@ -79,6 +83,7 @@ impl CmdParser { fsup, fsdown, nick, + fps, fs, fa, speed, diff --git a/src/mpv/mod.rs b/src/mpv/mod.rs index 89e8ebf..7233193 100644 --- a/src/mpv/mod.rs +++ b/src/mpv/mod.rs @@ -54,7 +54,6 @@ impl MpvControl { "--keep-open=no", "--idle=yes", "--player-operation-mode=pseudo-gui", - r#"--vf=lavfi="fps=60""#, ]) .arg(format!( "--input-ipc-server={}", @@ -81,7 +80,7 @@ impl MpvControl { self.mpv_command_tx .send(format!( "{{ \"command\": [\"set_property\", \"force-media-title\", \"{}\"] }}\n", - title + title.replace(r#"""#, r#"\""#) )) .await?; Ok(()) @@ -111,12 +110,13 @@ impl MpvControl { self.mpv_command_tx .send( r#"{ "command": ["keybind", "alt+r", "script-message dml:r"] } -{ "command": ["keybind", "alt+z", "script-message dml:fsdown"] } -{ "command": ["keybind", "alt+x", "script-message dml:fsup"] } -{ "command": ["keybind", "alt+i", "script-message dml:nick"] } -{ "command": ["keybind", "alt+b", "script-message dml:back"] } -{ "command": ["keybind", "alt+n", "script-message dml:next"] } -"# + { "command": ["keybind", "alt+z", "script-message dml:fsdown"] } + { "command": ["keybind", "alt+x", "script-message dml:fsup"] } + { "command": ["keybind", "alt+i", "script-message dml:nick"] } + { "command": ["keybind", "alt+b", "script-message dml:back"] } + { "command": ["keybind", "alt+n", "script-message dml:next"] } + { "command": ["keybind", "alt+f", "script-message dml:fps"] } + "# .into(), ) .await?; @@ -126,18 +126,54 @@ impl MpvControl { async fn handle_mpv_event(self: &Arc, line: &str, last_time: &mut i64) -> Result<()> { let j: serde_json::Value = serde_json::from_str(line)?; - if j.pointer("/data/w").is_some() { - let w = j.pointer("/data/w").ok_or(anyhow!("hme err 5"))?.as_u64().ok_or(anyhow!("hme err 6"))?; - let h = j.pointer("/data/h").ok_or(anyhow!("hme err 7"))?.as_u64().ok_or(anyhow!("hme err 8"))?; - if matches!(self.cm.site, crate::config::Site::BiliVideo) { - let _ = self.mtx.send(DMLMessage::SetVideoRes((w, h))).await; - self.mpv_command_tx.send("{ \"command\": [\"sub-remove\", \"1\"], \"async\": true }\n".into()).await?; - self.mpv_command_tx - .send(format!( - "{{ \"command\": [\"sub-add\", \"{}\"], \"async\": true }}\n", - self.ipc_manager.get_danmaku_socket_path() - )) - .await?; + if let Some(rid) = j.pointer("/request_id") { + if rid.as_u64().eq(&Some(114)) { + let w = j.pointer("/data/w").ok_or(anyhow!("hme err a1"))?.as_u64().unwrap(); + let h = j.pointer("/data/h").ok_or(anyhow!("hme err a2"))?.as_u64().unwrap(); + if matches!(self.cm.site, crate::config::Site::BiliVideo) { + let _ = self.mtx.send(DMLMessage::SetVideoRes((w, h))).await; + self.mpv_command_tx + .send( + r#"{ "command": ["sub-remove", "1"], "async": true } + "# + .into(), + ) + .await?; + self.mpv_command_tx + .send(format!( + "{{ \"command\": [\"sub-add\", \"{}\"], \"async\": true }}\n", + self.ipc_manager.get_danmaku_socket_path() + )) + .await?; + } + } else if rid.as_u64().eq(&Some(514)) { + match j.pointer("/data") { + Some(it) => match it.as_f64() { + Some(it) => { + self.cm.display_fps.write().await.0 = it.round() as u64; + } + None => {} + }, + None => {} + } + } else if rid.as_u64().eq(&Some(1919)) { + match j.pointer("/data") { + Some(it) => match it.as_f64() { + Some(it) => { + if self.cm.display_fps.read().await.1 == 0 && it < 59.0 { + self.mpv_command_tx + .send( + r#"{ "command": ["set_property", "vf", "fps=fps=60:round=near"] } + "# + .into(), + ) + .await?; + } + } + None => {} + }, + None => {} + } } } let event = j.pointer("/event").ok_or(anyhow!("hme err 1"))?.as_str().ok_or(anyhow!("hme err 2"))?; @@ -160,7 +196,16 @@ impl MpvControl { } } else if event.eq("file-loaded") { tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - let _ = self.mpv_command_tx.send("{ \"command\": [\"get_property\", \"video-params\"] }\n".into()).await; + let _ = self + .mpv_command_tx + .send( + r#"{ "command": ["get_property", "video-params"], "request_id": 114, "async": true } } + { "command": ["get_property", "display-fps"], "request_id": 514, "async": true } + { "command": ["get_property", "container-fps"], "request_id": 1919, "async": true } + "# + .into(), + ) + .await; } else if event.eq("client-message") && (chrono::Utc::now().timestamp_millis() - *last_time > 1000) { *last_time = chrono::Utc::now().timestamp_millis(); let cmds = cmdparser::CmdParser::new( @@ -212,6 +257,31 @@ impl MpvControl { let p = self.cm.bvideo_info.read().await.current_page.saturating_add(1); let _ = self.mtx.send(DMLMessage::GoToBVPage(p)).await; } + if cmds.fps { + let fps: u64 = { + let df = self.cm.display_fps.read().await; + let i = df.1 as usize % 3; + [df.0, 0u64, 60u64][i] + }; + if fps == 0 { + self.mpv_command_tx + .send( + r#"{ "command": ["set_property", "vf", ""] } + "# + .into(), + ) + .await?; + } else { + self.mpv_command_tx + .send(format!( + r#"{{ "command": ["set_property", "vf", "fps=fps={}:round=near"] }} + "#, + fps + )) + .await?; + } + self.cm.display_fps.write().await.1 += 1; + } } Ok(()) } diff --git a/src/streamfinder/bilibili.rs b/src/streamfinder/bilibili.rs index b081b23..fede547 100644 --- a/src/streamfinder/bilibili.rs +++ b/src/streamfinder/bilibili.rs @@ -1,11 +1,9 @@ use crate::config::ConfigManager; use anyhow::anyhow; use anyhow::Result; +use log::warn; use regex::Regex; -use std::{ - collections::HashMap, - sync::Arc, -}; +use std::{collections::HashMap, sync::Arc}; use url::Url; pub struct Bilibili { @@ -187,14 +185,14 @@ impl Bilibili { self.cm.bvideo_info.write().await.current_page = page; let cid = p.pointer("/cid").ok_or(anyhow!("gpi err c2"))?.as_u64().unwrap().to_string(); - let subtitle = p.pointer("/part").ok_or(anyhow!("gpi err c3"))?.as_str().unwrap(); + let final_title = if j.len() == 1 { + format!("{} - {}", &title, &artist) + } else { + let subtitle = p.pointer("/part").ok_or(anyhow!("gpi err c3"))?.as_str().unwrap(); + format!("{} - {} - {} - {}", &title, page, &subtitle, &artist) + }; - Ok(( - bvid, - cid, - format!("{} - {} - {} - {}", title, page, subtitle, &artist), - artist, - )) + Ok((bvid, cid, final_title, artist)) } pub async fn get_video(&self, page: usize) -> Result> { @@ -215,13 +213,12 @@ impl Bilibili { let mut param1 = Vec::new(); param1.push(("cid", cid.as_str())); param1.push(("bvid", bvid.as_str())); - param1.push(("qn", "120")); - param1.push(("otype", "json")); - param1.push(("fourk", "1")); - param1.push(("fnver", "0")); - param1.push(("fnval", "16")); + // param1.push(("qn", "126")); + // param1.push(("fourk", "1")); + // param1.push(("fnver", "0")); + param1.push(("fnval", "3024")); let client = reqwest::Client::builder() - .user_agent(crate::utils::gen_ua()) + .user_agent(crate::utils::gen_ua_safari()) .connect_timeout(tokio::time::Duration::from_secs(10)) .build()?; let resp = client @@ -234,99 +231,33 @@ impl Bilibili { .json::() .await?; // println!("{:?}", &resp); - let j = resp.pointer("/result").ok_or(anyhow!("get_video pje 1"))?; - if j.pointer("/dash").is_some() { - let dash_id = j - .pointer("/dash/video/0/id") - .ok_or(anyhow!("get_video pje 2"))? - .as_i64() - .ok_or(anyhow!("get_video ce 1"))?; - if j.pointer("/dash/video") - .ok_or(anyhow!("get_video pje 3"))? - .as_array() - .ok_or(anyhow!("cannot convert to vec"))? - .len() - > 1 - && dash_id - == j.pointer("/dash/video/0/id") - .ok_or(anyhow!("get_video pje 4"))? - .as_i64() - .ok_or(anyhow!(""))? - { - if j.pointer("/dash/video/0/codecid") - .ok_or(anyhow!("get_video pje n"))? - .as_i64() - .ok_or(anyhow!(""))? - == 12 - { - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 7"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 6"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - ret.push( - j.pointer("/dash/video/1/base_url") - .ok_or(anyhow!("get_video pje 5"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - } else { - ret.push( - j.pointer("/dash/video/1/base_url") - .ok_or(anyhow!("get_video pje 10"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 9"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 8"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - } - } else { - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 11"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 12"))? - .as_str() - .ok_or(anyhow!(""))? - .to_string(), - ); - } - } else { - let videos = j.pointer("/durl").ok_or(anyhow!("get_video pje 13"))?.as_array().ok_or(anyhow!(""))?; - for v in videos { - ret.push( - v.pointer("url").ok_or(anyhow!("get_video pje 14"))?.as_str().ok_or(anyhow!(""))?.to_string(), - ); + let j = resp.pointer("/result").ok_or(anyhow!("gv err b1"))?; + let mut videos = HashMap::new(); + let mut audios = HashMap::new(); + for ele in j.pointer("/dash/video").ok_or(anyhow!("gv err b2"))?.as_array().unwrap() { + let mut id = ele.pointer("/id").ok_or(anyhow!("gv err k3"))?.as_u64().unwrap() * 10; + if ele.pointer("/codecid").ok_or(anyhow!("gv err k31"))?.as_u64().eq(&Some(7)) { + id += 1; } + videos.insert( + id, + ele.pointer("/base_url").ok_or(anyhow!("gv err b4"))?.as_str().unwrap(), + ); + } + for ele in j.pointer("/dash/audio").ok_or(anyhow!("gv err b5"))?.as_array().unwrap() { + audios.insert( + ele.pointer("/id").ok_or(anyhow!("gv err b6"))?.as_u64().unwrap(), + ele.pointer("/base_url").ok_or(anyhow!("gv err b7"))?.as_str().unwrap(), + ); } + if let Some(ele) = j.pointer("/dash/flac/audio") { + audios.insert( + ele.pointer("/id").ok_or(anyhow!("gv err c1"))?.as_u64().unwrap() + 100, + ele.pointer("/base_url").ok_or(anyhow!("gv err c2"))?.as_str().unwrap(), + ); + } + ret.push(videos.iter().max_by_key(|x| x.0).unwrap().1.to_string()); + ret.push(audios.iter().max_by_key(|x| x.0).unwrap().1.to_string()); } else { let u = self.cm.bvideo_info.read().await.base_url.clone(); let (bvid, cid, title, _artist) = self.get_page_info(&u, page).await?; @@ -336,102 +267,46 @@ impl Bilibili { let mut param1 = Vec::new(); param1.push(("cid", cid.as_str())); param1.push(("bvid", bvid.as_str())); - param1.push(("qn", "120")); - param1.push(("otype", "json")); - param1.push(("fourk", "1")); - param1.push(("fnver", "0")); - param1.push(("fnval", "16")); + param1.push(("fnval", "3024")); let client = reqwest::Client::builder() - .user_agent(crate::utils::gen_ua()) + .user_agent(crate::utils::gen_ua_safari()) .connect_timeout(tokio::time::Duration::from_secs(10)) .build()?; let resp = client .get(&self.apiv) - .header("Referer", u) .header("Cookie", cookies) .query(¶m1) .send() .await? .json::() .await?; - let j = resp.pointer("/data").ok_or(anyhow!("get_video pje 15"))?; - if j.pointer("/dash").is_some() { - let dash_id = j.pointer("/dash/video/0/id").ok_or(anyhow!("get_video pje 16"))?.as_i64().unwrap(); - if j.pointer("/dash/video") - .ok_or(anyhow!("get_video pje 17"))? - .as_array() - .ok_or(anyhow!("cannot convert to vec"))? - .len() - > 1 - && dash_id == j.pointer("/dash/video/0/id").ok_or(anyhow!("get_video pje 18"))?.as_i64().unwrap() - { - if j.pointer("/dash/video/0/codecid").ok_or(anyhow!("get_video pje 19"))?.as_i64().unwrap() == 12 { - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 22"))? - .as_str() - .unwrap() - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 21"))? - .as_str() - .unwrap() - .to_string(), - ); - ret.push( - j.pointer("/dash/video/1/base_url") - .ok_or(anyhow!("get_video pje 20"))? - .as_str() - .unwrap() - .to_string(), - ); - } else { - ret.push( - j.pointer("/dash/video/1/base_url") - .ok_or(anyhow!("get_video pje 25"))? - .as_str() - .unwrap() - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 24"))? - .as_str() - .unwrap() - .to_string(), - ); - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 23"))? - .as_str() - .unwrap() - .to_string(), - ); - } - } else { - ret.push( - j.pointer("/dash/video/0/base_url") - .ok_or(anyhow!("get_video pje 26"))? - .as_str() - .unwrap() - .to_string(), - ); - ret.push( - j.pointer("/dash/audio/0/base_url") - .ok_or(anyhow!("get_video pje 27"))? - .as_str() - .unwrap() - .to_string(), - ); - } - } else { - let videos = j.pointer("/durl").ok_or(anyhow!("get_video pje 28"))?.as_array().unwrap(); - for v in videos { - ret.push(v.pointer("url").ok_or(anyhow!("get_video pje 29"))?.as_str().unwrap().to_string()); + let j = resp.pointer("/data").ok_or(anyhow!("gv err k1"))?; + let mut videos = HashMap::new(); + let mut audios = HashMap::new(); + for ele in j.pointer("/dash/video").ok_or(anyhow!("gv err k2"))?.as_array().unwrap() { + let mut id = ele.pointer("/id").ok_or(anyhow!("gv err k3"))?.as_u64().unwrap() * 10; + if ele.pointer("/codecid").ok_or(anyhow!("gv err k31"))?.as_u64().eq(&Some(7)) { + id += 1; } + videos.insert( + id, + ele.pointer("/base_url").ok_or(anyhow!("gv err k4"))?.as_str().unwrap(), + ); + } + for ele in j.pointer("/dash/audio").ok_or(anyhow!("gv err k5"))?.as_array().unwrap() { + audios.insert( + ele.pointer("/id").ok_or(anyhow!("gv err k6"))?.as_u64().unwrap(), + ele.pointer("/base_url").ok_or(anyhow!("gv err k7"))?.as_str().unwrap(), + ); + } + if let Some(ele) = j.pointer("/dash/flac/audio") { + audios.insert( + ele.pointer("/id").ok_or(anyhow!("gv err l1"))?.as_u64().unwrap() + 100, + ele.pointer("/base_url").ok_or(anyhow!("gv err l2"))?.as_str().unwrap(), + ); } + ret.push(videos.iter().max_by_key(|x| x.0).unwrap().1.to_string()); + ret.push(audios.iter().max_by_key(|x| x.0).unwrap().1.to_string()); } Ok(ret) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index b3623f0..ff178c5 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -26,6 +26,10 @@ pub fn gen_ua() -> String { // .into() } +pub fn gen_ua_safari() -> String { + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15".into() +} + // pub async fn js_call(js: &str, func: &str, args: &Vec<(u8, String)>) -> anyhow::Result> { pub async fn js_call(js: &str) -> anyhow::Result> { let mut rt =