use once_cell::sync::Lazy;
use reqwest::{
header::{self, HeaderMap},
Url,
};
use serde::Deserialize;
use crate::{
utils::{self, Client},
Error, Extract, FinaResult, Finata, Origin, Track,
};
static HEADERS: Lazy<HeaderMap> = Lazy::new(|| {
crate::hdmap! {
header::USER_AGENT => utils::UA.clone(),
header::REFERER => "https://weibo.com",
}
});
pub struct Live {
id: String,
client: Client,
}
impl Live {
pub fn new(url: &str) -> Result<Self, Error> {
let url = Url::parse(url)?;
match url
.path_segments()
.map(|p| p.filter(|s| !s.is_empty()).next_back())
.flatten()
{
Some(id) => Ok(Self {
id: dbg!(id).to_string(),
client: Client::with_header(HEADERS.clone()),
}),
None => Err(Error::InvalidUrl { url }),
}
}
async fn _extract(&self) -> FinaResult {
let url = format!(
"https://weibo.com/l/!/2/wblive/room/show_pc_live.json?live_id={}",
self.id
);
let response = self
.client
.send_json_request::<Response>(url.parse()?)
.await?;
let pl = self
.client
.client()
.get(response.data.replay_origin_url)
.send()
.await?
.text()
.await?;
let vi_list = pl
.lines()
.filter(|s| !s.starts_with('#'))
.map(|s| format!("https://live.video.weibocdn.com/{}", s));
let tracks = vi_list
.map(|url| -> Result<_, Error> { Ok(Track::Video(url.parse()?)) })
.collect::<Result<_, Error>>()?;
let origin = Origin::new(tracks, String::new());
Ok(Finata::new(vec![origin], response.data.title))
}
}
#[async_trait::async_trait]
impl Extract for Live {
async fn extract(&mut self) -> crate::FinaResult {
self._extract().await
}
}
#[derive(Debug, Clone, Deserialize)]
struct ResponseData {
pub replay_origin_url: String,
pub title: String,
}
#[derive(Debug, Clone, Deserialize)]
struct Response {
pub data: ResponseData,
}