1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#[macro_export]
macro_rules! value_to_string {
    ($v: expr) => {
        match $v {
            serde_json::Value::String(ref s) => Some(s.to_owned()),
            _ => None,
        }
    };
    ($v: expr, $($or: expr),+) => {
        match $v {
            serde_json::Value::String(ref s) => Some(s.to_owned()),
            _ => $crate::value_to_string!($($or),+),
        }
    };
}
#[macro_export]
macro_rules! parse_json {
    ($s: expr) => {
        match serde_json::from_str($s) {
            Ok(v) => v,
            Err(_) => return Err(anyhow::anyhow!(format!("Invalid json data: {}", $s))),
        }
    };
    ($s: expr, $ty: ty) => {
        match serde_json::from_str($s) {
            Ok::<$ty, _>(v) => v,
            Err(_) => return Err(anyhow::anyhow!(format!("Invalid json data: {}", $s))),
        }
    };
}
#[macro_export]
macro_rules! get {
    ($v: expr) => {
        $v
    };
    ($v: expr, $($vn: expr),+) => {
        match $v {
            serde_json::Value::Null => $crate::get!($($vn),+),
            _ => $v,
        }
    }
}

pub mod proxy;
pub mod command;
pub mod extractors;
pub mod parsers;

use anyhow::Result;
use std::process::Command;
use std::io::Result as IoResult;
use proxy::ProxyAddr;
use parsers::Url;

type ResultInfo = Result<MediaInfo>;

#[derive(Debug)]
pub struct MediaInfo {
    pub url: Url,
    pub title: Option<String>,
    pub referrer: Option<String>,
    pub user_agent: Option<String>,
}
pub struct Setting<'a> {
    pub proxy_addr: Option<ProxyAddr<'a>>,
    pub cookie: Option<&'a str>,
}

impl MediaInfo {
    pub fn new(url: Url, title: Option<String>, referrer: Option<String>) -> Self {
        Self::with_ua(url, title, referrer, None)
    }
    pub fn with_ua(url: Url, title: Option<String>, referrer: Option<String>, user_agent: Option<String>) -> Self {
        Self { url, title, referrer, user_agent }
    }
    pub fn default_ua(url: Url, title: Option<String>, referrer: Option<String>) -> Self {
        Self::with_ua(url, title, referrer, Some(String::from("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.4 Safari/537.36")))
    }
    pub fn play(&self) -> IoResult<()> {
        self.as_command().output()?;
        Ok(())
    }
    /// Spwans commands to run mpv
    pub fn as_command(&self) -> Command {
        let Url { videos, audios } = &self.url;
        let mut cmd = Command::new("mpv");
        match videos.len() {
            0 => cmd.args(audios.iter())
                .arg("--force-window=immediate"),
            1 => cmd.arg(&videos[0])
                .args(audios
                    .iter()
                    .map(|a| format!("--audio-file={}", a))
                ),
            _ => cmd.args(videos.iter())
                .args(audios
                    .iter()
                    .map(|a| format!("--audio-file={}", a))
                )
                .arg("--merge-files"),
        };
        if let Some(referrer) = &self.referrer {
            cmd.arg(format!("--referrer={}", referrer));
        }
        if let Some(title) = &self.title {
            cmd.arg(format!("--title={}", title));
        }
        if let Some(user_agent) = &self.user_agent {
            cmd.arg(format!("--user-agent={}", user_agent));
        }
        cmd.arg("--no-ytdl");
        cmd
    }
}
impl<'a> From<ProxyAddr<'a>> for Setting<'a> {
    fn from(proxy_addr: ProxyAddr<'a>) -> Setting<'a> {
       Setting { proxy_addr: Some(proxy_addr), cookie: None }
    }
}
impl<'a> From<Option<ProxyAddr<'a>>> for Setting<'a> {
    fn from(proxy_addr: Option<ProxyAddr<'a>>) -> Setting<'a> {
       Setting { proxy_addr: proxy_addr, cookie: None }
    }
}
impl<'a> AsRef<Option<ProxyAddr<'a>>> for Setting<'a> {
    fn as_ref(&self) -> &Option<ProxyAddr<'a>> {
        &self.proxy_addr
    }
}