Skip to content

Commit

Permalink
fix: get youtube live status by channel_Id instead of video_id
Browse files Browse the repository at this point in the history
  • Loading branch information
limitcool committed Jul 28, 2023
1 parent 9267935 commit 01a149f
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bilistream"
version = "0.1.7"
version = "0.1.9"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,23 @@ Interval: 60
Platform: Twitch
# B站推流账号Cookie
BiliLive:
SESSDATA:
bili_jct:
SESSDATA:
bili_jct:
DedeUserID: 2235894
DedeUserID__ckMd5:
DedeUserID__ckMd5:
Room: 660428
BiliRtmpUrl: rtmp://live-push.bilivideo.com/live-bvc/
# BiliRtmpUrl: B站开播设置页面的服务器地址
# BiliRtmpUrl: B站开播设置页面的服务器地址
BiliRtmpKey: "?streamname=live_0000000_0000000&key=xxxxxxxxxxb8289c6acc97xxxxxxxxx&schedule=rtmp&pflag=1"
# BiliRtmpKey: B站开播设置页面的串流密钥,需注意,由于是?号开头的,本行需要对内容加双引号
# Twitch 直播间Id
Twitch:
# Room: maximilian_dood
Room:
Room:
# youtube 需要使用Youtube API AK以及Yt-dlp
Youtube:
Room:
AccessToken:
Room: UC1zFJrfEKvCixhsjNSb1toQ
AccessToken:
# youtube 预告类型直播转播请填写以下内容
YoutubePreviewLive:
ChannelId: UC1zFJrfEKvCixhsjNSb1toQ
Expand Down
93 changes: 93 additions & 0 deletions src/plugins/live.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,96 @@ pub async fn get_live_id_by_jump(channel_name: &str) -> Result<String, Box<dyn E

Err("获取video_id失败".into())
}

pub async fn get_youtube_live_status(channel_name: &str) -> Result<bool, Box<dyn Error>> {
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(1);
let raw_client = reqwest::Client::builder()
.cookie_store(true)
// 设置超时时间为30秒
.timeout(Duration::new(30, 0))
.build()
.unwrap();
let client = ClientBuilder::new(raw_client.clone())
.with(RetryTransientMiddleware::new_with_policy(retry_policy))
.build();
let url = format!("https://www.youtube.com/channel/{}/live", channel_name);
tracing::debug!("{}", url);
// println!("channel地址为:{}", url);
let res = client.get(&url).send().await?;
let body = res.text().await?;
// 保存body为文件,后缀为html
let html = prettyish_html::prettify(body.as_str());
// let mut file = std::fs::File::create("jump.html").unwrap();
// std::io::Write::write_all(&mut file, html.as_bytes()).unwrap();

let re = regex::Regex::new(r#"\s*<script nonce=".*">var ytInitialData = (.*);\s*?</script>"#)
.unwrap();
// if re.is_match(html.as_str()) {
// let live_id = re.captures(html.as_str()).unwrap().get(1).unwrap().as_str();
// let live_id = live_id.split("\"").nth(1).unwrap();
// println!("{}", live_id);
// } else {
// println!("no match");
// }
for cap in re.captures(html.as_str()) {

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (x86_64-linux)

for loop over an `Option`. This is more readably written as an `if let` statement

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (x86_64-macos)

for loop over an `Option`. This is more readably written as an `if let` statement

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (aarch64-macos)

for loop over an `Option`. This is more readably written as an `if let` statement

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (x86_64-linux-musl, ubuntu-latest, stable, x86_64-unknown-linux-musl, true)

for loop over an `Option`. This is more readably written as an `if let` statement

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (x86_64-windows)

for loop over an `Option`. This is more readably written as an `if let` statement

Check warning on line 308 in src/plugins/live.rs

View workflow job for this annotation

GitHub Actions / Dist (aarch64-linux)

for loop over an `Option`. This is more readably written as an `if let` statement
let json = cap.get(1).unwrap().as_str();
let j: Value = serde_json::from_str(json).unwrap();
let live_status = j["contents"]["twoColumnWatchNextResults"]["results"]["results"]
["contents"][0]["videoPrimaryInfoRenderer"]["viewCount"]["videoViewCountRenderer"]
["isLive"]
.to_string();
// let mut file = std::fs::File::create("jump_live_id.json").unwrap();
// std::io::Write::write_all(&mut file, json.as_bytes()).unwrap();
// println!("live status{}", live_status);
if live_status != "true" {
return Ok(false);
} else {
return Ok(true);
}
}

// Err("获取video_id失败".into())
return Ok(false);
}

// 测试get_room_id 传入UC1zFJrfEKvCixhsjNSb1toQ
#[cfg(test)]
mod tests {
use super::*;

macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn test_get_room_id() {
let channel_id = "GameSpun";
let r = aw!(get_channel_id(channel_id)).unwrap();
println!("id:{}", r);
}
#[test]
fn test_get_live_id() {
let channel_id = "UC1zFJrfEKvCixhsjNSb1toQ";
let r = aw!(get_live_id(channel_id)).unwrap();
println!("id:{}", r);
}
#[test]
fn test_json_path_to_string() {
let re = json_path_to_map_string("x.contents.twoColumnWatchNextResults.results.results.contents[0].videoPrimaryInfoRenderer.videoActions.menuRenderer.topLevelButtons[0].toggleButtonRenderer.defaultNavigationEndpoint.modalEndpoint.modal.modalWithTitleAndButtonRenderer.button.buttonRenderer.navigationEndpoint.signInEndpoint.nextEndpoint.watchEndpoint.videoId");
println!("re:{}", re);
}
#[test]
fn test_get_jump_url() {
// lofi girl
let channel_id = "UCSJ4gkVC6NrvII8umztf0Ow";
let r: String = aw!(get_live_id_by_jump(channel_id)).unwrap();
println!("url:{}", r);
}
#[test]
fn tes_get_youtube_status() {
let channel_id = "UCcHWhgSsMBemnyLhg6GL1vA";
let r = aw!(get_youtube_live_status(channel_id)).unwrap();
println!("直播状态为:{}", r);
}
}
37 changes: 19 additions & 18 deletions src/plugins/youtube.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use reqwest_middleware::ClientWithMiddleware;
use std::error::Error;
use std::process::Command;

use super::Live;
use super::{get_youtube_live_status, Live};
pub struct Youtube {
pub room: String,
pub access_token: String,
Expand All @@ -16,22 +16,23 @@ impl Live for Youtube {
&self.room
}
async fn get_status(&self) -> Result<bool, Box<dyn Error>> {
let res = self.client
.get(format!("https://www.googleapis.com/youtube/v3/videos?part=liveStreamingDetails&id={}&key={}", self.room.replace("\"", ""), self.access_token))
.send()
.await?;
let res = res.json::<serde_json::Value>().await?;
// println!("{:?}", self.room);
// println!("re{}", res);
// println!(
// "AT{}",
// res["items"][0]["liveStreamingDetails"]["actualStartTime"]
// );
if res["items"][0]["liveStreamingDetails"]["actualStartTime"].is_null() {
Ok(false)
} else {
Ok(true)
}
// let res = self.client
// .get(format!("https://www.googleapis.com/youtube/v3/videos?part=liveStreamingDetails&id={}&key={}", self.room.replace("\"", ""), self.access_token))
// .send()
// .await?;
// let res = res.json::<serde_json::Value>().await?;
// // println!("{:?}", self.room);
// // println!("re{}", res);
// // println!(
// // "AT{}",
// // res["items"][0]["liveStreamingDetails"]["actualStartTime"]
// // );
// if res["items"][0]["liveStreamingDetails"]["actualStartTime"].is_null() {
// Ok(false)
// } else {
// Ok(true)
// }
get_youtube_live_status(&self.room).await
}
async fn get_real_m3u8_url(&self) -> Result<String, Box<dyn Error>> {
return self.ytdlp();
Expand All @@ -54,7 +55,7 @@ impl Youtube {
let mut command = Command::new("yt-dlp");
command.arg("-g");
command.arg(format!(
"https://www.youtube.com/watch?v={}",
"https://www.youtube.com/channel{}/live",
self.room.as_str().replace("\"", "")
));
match command.status().unwrap().code() {
Expand Down

0 comments on commit 01a149f

Please sign in to comment.