extern crate hyper;
extern crate hyper_tls;
extern crate tokio;
extern crate futures;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use futures::{Future, Stream};
use std::sync::{Arc, Mutex};
use std::borrow::Cow;
#[derive(Debug)]
pub enum FetchError {
Http(hyper::Error),
Json(serde_json::Error),
}
impl From<hyper::Error> for FetchError {
fn from(err: hyper::Error) -> FetchError {
FetchError::Http(err)
}
}
impl From<serde_json::Error> for FetchError {
fn from(err: serde_json::Error) -> FetchError {
FetchError::Json(err)
}
}
pub trait Request {
type Response: serde::de::DeserializeOwned + std::fmt::Debug + std::marker::Send;
fn url(&self) -> Cow<'static, str>;
}
#[derive(Deserialize, Debug)]
pub struct SerieTraduzione {
id_serie: usize,
nome_serie: String,
link_serie: String,
id_thetvdb: usize,
num_stagione: usize,
num_episodio: usize,
stato: String,
}
pub struct ReqSerieTraduzione;
impl Request for ReqSerieTraduzione {
type Response = SerieTraduzione;
fn url(&self) -> Cow<'static, str> {
Cow::Borrowed("https://www.subspedia.tv/API/serie_traduzione")
}
}
#[derive(Deserialize, Debug)]
pub struct Serie {
id_serie: usize,
nome_serie: String,
link_serie: String,
id_thetvdb: usize,
stato: String,
anno: usize
}
pub struct ReqElencoSerie;
impl Request for ReqElencoSerie {
type Response = Serie;
fn url(&self) -> Cow<'static, str> {
Cow::Borrowed("https://www.subspedia.tv/API/elenco_serie")
}
}
#[derive(Deserialize, Debug)]
pub struct Sottotitolo {
id_serie: usize,
nome_serie: String,
ep_titolo: String,
num_stagione: usize,
num_episodio: usize,
immagine: String,
link_sottotitoli: String,
link_serie: String,
link_file: String,
descrizione: String,
id_thetvdb: usize,
data_uscita: String,
grazie: usize
}
pub struct ReqUltimiSottotitoli;
impl Request for ReqUltimiSottotitoli {
type Response = Sottotitolo;
fn url(&self) -> Cow<'static, str> {
Cow::Borrowed("https://www.subspedia.tv/API/ultimi_sottotitoli")
}
}
pub struct ReqSottotitoliSerie {
id: usize,
}
impl ReqSottotitoliSerie {
pub fn new(id: usize) -> ReqSottotitoliSerie {
ReqSottotitoliSerie {id}
}
}
impl Request for ReqSottotitoliSerie {
type Response = Sottotitolo;
fn url(&self) -> Cow<'static, str> {
Cow::Owned(format!("https://www.subspedia.tv/API/sottotitoli_serie?serie={}", self.id))
}
}
pub fn get<R: 'static + Request>(req: R) -> Result<Vec<R::Response>, FetchError>
{
let url = req.url().parse().unwrap();
let result = Arc::new(Mutex::new(Vec::new()));
let tmp = Arc::clone(&result);
tokio::run(futures::lazy(move || {
fetch_json::<R::Response>(url)
.map(move |mut serie| {
tmp.lock().unwrap().append(&mut serie);
})
.map_err(|e| {
match e {
FetchError::Http(e) => eprintln!("http error: {}", e),
FetchError::Json(e) => eprintln!("json parsing error: {}", e),
}
})
}));
Ok(Arc::try_unwrap(result).unwrap().into_inner().unwrap())
}
fn fetch_json<T>(url: hyper::Uri) -> impl Future<Item=Vec<T>, Error=FetchError>
where T: serde::de::DeserializeOwned + std::fmt::Debug
{
let https = hyper_tls::HttpsConnector::new(4).unwrap();
let client = hyper::Client::builder()
.build::<_, hyper::Body>(https);
client
.get(url)
.and_then(|res| {
res.into_body().concat2()
})
.from_err::<FetchError>()
.and_then(|body| {
let serie = serde_json::from_slice(&body)?;
Ok(serie)
})
}