You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
5.2 KiB

use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt;
use std::io;
use std::marker::PhantomData;
use std::process::ExitStatus;
use std::string::FromUtf8Error;
use tokio::task::JoinError;
use url::Url;
extern crate quick_xml;
extern crate reqwest;
extern crate serde_json;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct InvidiousVideo {
pub video_id: String,
}
#[derive(Deserialize, Debug)]
pub struct VideoURL {
pub url: Url,
}
#[derive(Deserialize, Debug)]
pub struct VideoData {
#[serde(default)]
pub requested_formats: Vec<VideoURL>,
#[serde(default)]
pub url: Option<Url>,
#[serde(deserialize_with = "convert_to_u64")]
pub duration: u64,
pub id: String,
pub title: String,
#[serde(default)]
pub thumbnail: Option<Url>,
#[serde(default)]
pub is_live: Option<bool>,
#[serde(skip)]
pub json: String,
}
#[derive(Debug)]
pub struct YoutubeDLError {
pub status: ExitStatus,
pub stdout: String,
pub stderr: String,
}
#[derive(Debug)]
pub enum Error {
IO(io::Error),
JoinError(JoinError),
Reqwest(reqwest::Error),
QuickXML(quick_xml::Error),
SerdeJSON(serde_json::Error),
FromUtf8Error(FromUtf8Error),
YoutubeDL(YoutubeDLError),
}
impl From<io::Error> for Error {
#[inline]
fn from(error: io::Error) -> Error {
Error::IO(error)
}
}
impl From<JoinError> for Error {
#[inline]
fn from(error: JoinError) -> Error {
Error::JoinError(error)
}
}
impl From<reqwest::Error> for Error {
#[inline]
fn from(error: reqwest::Error) -> Error {
Error::Reqwest(error)
}
}
impl From<quick_xml::Error> for Error {
#[inline]
fn from(error: quick_xml::Error) -> Error {
Error::QuickXML(error)
}
}
impl From<serde_json::Error> for Error {
#[inline]
fn from(error: serde_json::Error) -> Error {
Error::SerdeJSON(error)
}
}
impl From<FromUtf8Error> for Error {
#[inline]
fn from(error: FromUtf8Error) -> Error {
Error::FromUtf8Error(error)
}
}
fn convert_to_u64<'de, D>(deserializer: D) -> std::result::Result<u64, D::Error>
where
D: Deserializer<'de>,
{
struct ConvertToU64<T>(PhantomData<fn() -> T>);
impl<'de> Visitor<'de> for ConvertToU64<u64> {
type Value = u64;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an integer between 0 and 2^63")
}
fn visit_i8<E>(self, value: i8) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
use std::u64;
if value >= 0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
fn visit_i16<E>(self, value: i16) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
use std::u64;
if value >= 0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
fn visit_i32<E>(self, value: i32) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
use std::u64;
if value >= 0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
fn visit_i64<E>(self, value: i64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
use std::u64;
if value >= 0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
fn visit_u8<E>(self, value: u8) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(u64::from(value))
}
fn visit_u16<E>(self, value: u16) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(u64::from(value))
}
fn visit_u32<E>(self, value: u32) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(u64::from(value))
}
fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(value)
}
fn visit_f32<E>(self, value: f32) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
let value = value.ceil();
if value >= 0.0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
fn visit_f64<E>(self, value: f64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
let value = value.ceil();
if value >= 0.0 {
Ok(value as u64)
} else {
Err(E::custom(format!("u64 out of range: {}", value)))
}
}
}
deserializer.deserialize_any(ConvertToU64(PhantomData))
}