rsget_lib 0.3.0

Library to get information about and download livestreams
Documentation
use crate::Streamable;
use regex::Regex;
use serde_json;
use serde_json::Value;

use stream_lib::StreamType;

use crate::utils::error::RsgetError;
use crate::utils::error::StreamError;

use crate::utils::downloaders::DownloadClient;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Author {
    pub uid: String,
    pub avatar_larger: LabelTop,
    pub birthday: String,
    pub custom_verify: String,
    pub is_verified: bool,
    pub nickname: String,
    pub user_mode: i64,
    pub short_id: String,
    pub hide_location: bool,
    pub gender: i64,
    pub secret: i64,
    pub user_period: i64,
    pub avatar_medium: LabelTop,
    pub signature: String,
    pub avatar_thumb: LabelTop,
    pub weibo_verify: String,
    pub unique_id: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Comments {
    pub status: i64,
    pub from_author: bool,
    #[serde(skip_serializing)]
    pub reply_comment: Vec<String>,
    pub text: String,
    pub cid: String,
    pub digg_count: i64,
    #[serde(skip_serializing)]
    pub text_extra: Vec<String>,
    pub create_time: i64,
    pub reply_id: String,
    pub user: User,
    pub aweme_id: String,
    pub user_digged: i64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LabelTop {
    pub url_list: Vec<String>,
    pub uri: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Music {
    pub cover_hd: LabelTop,
    pub status: i64,
    pub owner_nickname: String,
    pub user_count: i64,
    pub is_video_self_see: bool,
    pub title: String,
    pub play_url: LabelTop,
    pub owner_id: String,
    #[serde(skip_serializing)]
    pub app_unshelve_info: Value,
    pub mid: String,
    pub author_name: String,
    pub schema_url: String,
    pub is_only_owner_use: bool,
    pub source: i64,
    pub cover_large: LabelTop,
    pub owner_handle: String,
    pub is_del_video: bool,
    pub cover_thumb: LabelTop,
    pub cover_medium: LabelTop,
    pub music_name: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PlayAddr {
    pub url_list: Vec<String>,
    pub url_key: String,
    pub uri: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PolicyVersion {
    #[serde(rename = "GLOBAL")]
    pub _global: Option<i64>,
    #[serde(rename = "SE")]
    pub _se: Option<i64>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RiskInfos {
    pub warn: bool,
    pub content: String,
    pub risk_sink: bool,
    #[serde(rename = "type")]
    pub _type: i64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TikTokRoot {
    pub risk_infos: RiskInfos,
    pub label_top: LabelTop,
    pub author_user_id: i64,
    pub item_comment_settings: i64,
    pub rate: i64,
    pub create_time: i64,
    pub video: Video,
    pub comments: Vec<Comments>,
    pub aweme_id: String,
    #[serde(skip_serializing)]
    pub video_labels: Vec<String>,
    pub is_vr: bool,
    pub vr_type: i64,
    pub statistics: Statistics,
    pub author: Author,
    pub prevent_download: bool,
    pub cmt_swt: bool,
    pub share_url: String,
    pub is_ads: bool,
    pub comment_count: i64,
    pub music: Music,
    pub bodydance_score: i64,
    pub xigua_task: XiguaTask,
    pub is_hash_tag: i64,
    pub status: Status,
    pub sort_label: String,
    pub share_info: ShareInfo,
    #[serde(skip_serializing)]
    pub video_text: Vec<String>,
    pub is_top: i64,
    pub aweme_type: i64,
    pub desc: String,
    pub group_id: String,
    #[serde(skip_serializing)]
    pub geofencing: Vec<String>,
    pub region: String,
    pub is_pgcshow: bool,
    pub is_relieve: bool,
    pub text_extra: Vec<TextExtra>,
    pub user_digged: i64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ShareInfo {
    pub share_weibo_desc: String,
    pub bool_persist: i64,
    pub share_quote: String,
    pub share_title: String,
    pub share_signature_desc: String,
    pub share_signature_url: String,
    pub share_link_desc: String,
    pub share_url: String,
    pub share_desc: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Statistics {
    pub comment_count_str: String,
    pub digg_count_str: String,
    pub forward_count: i64,
    pub digg_count: i64,
    pub share_count_str: String,
    pub play_count: i64,
    pub comment_count: i64,
    pub aweme_id: String,
    pub share_count: i64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Status {
    pub private_status: i64,
    pub reviewed: i64,
    pub is_prohibited: bool,
    pub with_goods: bool,
    pub is_private: bool,
    pub download_status: i64,
    pub is_delete: bool,
    pub with_fusion_goods: bool,
    pub self_see: bool,
    pub in_reviewing: bool,
    pub allow_share: bool,
    pub allow_comment: bool,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TextExtra {
    pub start: i64,
    pub end: i64,
    pub hashtag_name: String,
    #[serde(rename = "type")]
    pub _type: i64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct User {
    pub youtube_channel_title: String,
    pub share_qrcode_uri: String,
    pub app_id: i64,
    pub original_music_qrcode: Option<String>,
    pub is_gov_media_vip: bool,
    pub live_commerce: bool,
    pub account_region: String,
    pub user_period: i64,
    pub reflow_page_gid: i64,
    pub is_binded_weibo: bool,
    #[serde(rename = "video_icon_virtual_URI")]
    pub video_icon_virtual_uri: String,
    pub risk_flag: i64,
    pub school_name: String,
    pub download_setting: i64,
    pub cv_level: String,
    pub custom_verify: String,
    pub special_lock: i64,
    pub user_canceled: bool,
    pub shield_comment_notice: i64,
    #[serde(skip_serializing)]
    pub type_label: Vec<String>,
    pub hide_location: bool,
    pub gender: i64,
    pub video_icon: LabelTop,
    pub school_poi_id: String,
    pub live_agreement: i64,
    pub is_phone_binded: bool,
    pub prevent_download: bool,
    pub weibo_schema: String,
    pub create_time: i64,
    pub has_insights: bool,
    pub react_setting: i64,
    pub google_account: String,
    pub community_discipline_status: i64,
    pub user_mode: i64,
    pub need_recommend: i64,
    pub update_before: i64,
    pub has_register_notice: i64,
    pub room_id: i64,
    pub avatar_medium: LabelTop,
    pub has_orders: bool,
    pub reflow_page_uid: i64,
    pub cover_url: Vec<LabelTop>,
    pub duet_setting: i64,
    pub language: String,
    #[serde(skip_serializing)]
    pub geofencing: Vec<String>,
    pub ins_id: String,
    pub unique_id_modify_time: i64,
    pub school_type: i64,
    pub twitter_name: String,
    pub avatar_uri: String,
    pub signature: String,
    pub weibo_verify: String,
    pub comment_setting: i64,
    pub with_fusion_shop_entry: bool,
    pub youtube_channel_id: String,
    pub avatar_larger: LabelTop,
    pub enterprise_verify_reason: String,
    pub user_rate: i64,
    pub live_verify: i64,
    pub short_id: String,
    pub secret: i64,
    pub avatar_thumb: LabelTop,
    pub is_verified: bool,
    pub hide_search: bool,
    pub with_commerce_entry: bool,
    pub download_prompt_ts: i64,
    pub twitter_id: String,
    pub has_email: bool,
    #[serde(skip_serializing)]
    pub policy_version: PolicyVersion,
    pub region: String,
    pub uid: String,
    pub bind_phone: String,
    pub weibo_url: String,
    pub live_agreement_time: i64,
    pub weibo_name: String,
    pub commerce_user_level: i64,
    pub verify_info: String,
    pub apple_account: i64,
    pub accept_private_policy: bool,
    pub shield_digg_notice: i64,
    pub verification_type: i64,
    pub neiguang_shield: i64,
    pub live_rec_level: i64,
    pub authority_status: i64,
    pub enterprise_verify: bool,
    pub birthday: String,
    pub is_ad_fake: bool,
    pub nickname: String,
    pub shield_follow_notice: i64,
    pub original_music_cover: Option<String>,
    pub creator_level: i64,
    pub nickname_lock: i64,
    pub status: i64,
    pub unique_id: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Video {
    pub ratio: String,
    pub origin_cover: LabelTop,
    pub play_addr: PlayAddr,
    pub cover: LabelTop,
    pub height: i64,
    pub width: i64,
    pub download_addr: PlayAddr,
    pub has_watermark: bool,
    pub play_addr_lowbr: PlayAddr,
    pub dynamic_cover: LabelTop,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct XiguaTask {
    pub is_xigua_task: bool,
}

#[derive(Clone, Debug)]
pub struct TikTok {
    pub url: String,
    pub video_id: String,
    pub tiktok: TikTokRoot,
    client: DownloadClient,
}

impl Streamable for TikTok {
    fn new(url: String) -> Result<Box<TikTok>, StreamError> {
        let dc = DownloadClient::new()?;
        let site_req = dc.make_request(&url, None)?;
        let res: String = dc.download_to_string(site_req)?;

        let url_re = Regex::new(
            r"^(?:https?://)?(?:www\.)?(?:m\.)?tiktok\.com/v/([a-zA-Z0-9]+)(?:\.html)?",
        )?;
        let json_re = Regex::new(r"var data = (\{.+\});")?;
        let id_cap = url_re.captures(&url).ok_or_else(|| {
            StreamError::Rsget(RsgetError::new("[TIKTOK] Regex did not find any video id"))
        })?;
        let json_cap = json_re.captures(&res).ok_or_else(|| {
            StreamError::Rsget(RsgetError::new("[TIKTOK] Regex did not find any json"))
        })?;
        debug!("{}", &json_cap[1]);
        let tik: TikTokRoot = serde_json::from_str(&json_cap[1])?;

        let ret_val = TikTok {
            client: dc,
            url: url.clone(),
            video_id: String::from(&id_cap[1]),
            tiktok: tik,
        };
        info!("{:#?}", &ret_val);
        Ok(Box::new(ret_val))
    }

    fn get_title(&self) -> Option<String> {
        Some(self.tiktok.desc.clone())
    }

    fn get_author(&self) -> Option<String> {
        Some(self.tiktok.author.nickname.clone())
    }

    fn is_online(&self) -> bool {
        true
    }

    fn get_stream(&self) -> Result<StreamType, StreamError> {
        Ok(StreamType::Chuncked(
            self.client
                .rclient
                .get(&self.tiktok.video.download_addr.url_list[0])
                .build()?,
        ))
    }

    fn get_ext(&self) -> String {
        String::from("mp4")
    }

    fn get_default_name(&self) -> String {
        format!(
            "{}-{}-{}.{}",
            self.video_id,
            self.get_title().unwrap(),
            self.get_author().unwrap(),
            self.get_ext()
        )
    }
    fn get_reqwest_client(&self) -> &reqwest::Client {
        &self.client.rclient
    }
}