Final crate restructure I hope.
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "hammond-downloader"
|
||||
version = "0.1.0"
|
||||
authors = ["Jordan Petridis <jordanpetridis@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
hammond-data = {path = "../hammond-data"}
|
||||
error-chain = "0.11.0"
|
||||
log = "0.3.8"
|
||||
loggerv = "0.3.0"
|
||||
reqwest = "0.7.3"
|
||||
hyper = "0.11.2"
|
||||
diesel = { version = "0.16.0", features = ["sqlite"] }
|
||||
diesel_codegen = { version = "0.16.0", features = ["sqlite"] }
|
||||
rss = { version = "1.1.0", features = ["from_url"]}
|
||||
dotenv = "*"
|
||||
@@ -0,0 +1,112 @@
|
||||
use reqwest;
|
||||
use hyper::header::*;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use std::fs::{rename, DirBuilder, File};
|
||||
use std::io::{BufWriter, Read, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use errors::*;
|
||||
use hammond_data::dbqueries;
|
||||
use hammond_data::models::Episode;
|
||||
use hammond_data::DL_DIR;
|
||||
|
||||
// Adapted from https://github.com/mattgathu/rget .
|
||||
// I never wanted to write a custom downloader.
|
||||
// Sorry to those who will have to work with that code.
|
||||
// Would much rather use a crate,
|
||||
// or bindings for a lib like youtube-dl(python),
|
||||
// But cant seem to find one.
|
||||
pub fn download_to(target: &str, url: &str) -> Result<()> {
|
||||
let mut resp = reqwest::get(url)?;
|
||||
info!("GET request to: {}", url);
|
||||
|
||||
if resp.status().is_success() {
|
||||
let headers = resp.headers().clone();
|
||||
|
||||
let ct_len = headers.get::<ContentLength>().map(|ct_len| **ct_len);
|
||||
let ct_type = headers.get::<ContentType>().unwrap();
|
||||
ct_len.map(|x| info!("File Lenght: {}", x));
|
||||
info!("Content Type: {:?}", ct_type);
|
||||
|
||||
info!("Save destination: {}", target);
|
||||
|
||||
let chunk_size = match ct_len {
|
||||
Some(x) => x as usize / 99,
|
||||
None => 1024 as usize, // default chunk size
|
||||
};
|
||||
|
||||
let out_file = format!("{}.part", target);
|
||||
let mut writer = BufWriter::new(File::create(&out_file)?);
|
||||
|
||||
loop {
|
||||
let mut buffer = vec![0; chunk_size];
|
||||
let bcount = resp.read(&mut buffer[..]).unwrap();
|
||||
buffer.truncate(bcount);
|
||||
if !buffer.is_empty() {
|
||||
writer.write(buffer.as_slice()).unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
rename(out_file, target)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Initial messy prototype, queries load alot of not needed stuff.
|
||||
pub fn latest_dl(connection: &SqliteConnection, limit: u32) -> Result<()> {
|
||||
let pds = dbqueries::get_podcasts(connection)?;
|
||||
|
||||
pds.iter()
|
||||
// TODO when for_each reaches stable:
|
||||
// Remove all the ugly folds(_) and replace map() with for_each().
|
||||
.map(|x| -> Result<()> {
|
||||
let mut eps;
|
||||
if limit == 0 {
|
||||
eps = dbqueries::get_pd_episodes(connection, &x)?;
|
||||
} else {
|
||||
eps = dbqueries::get_pd_episodes_limit(connection, &x, limit)?;
|
||||
}
|
||||
|
||||
// It might be better to make it a hash of the title
|
||||
let dl_fold = format!("{}/{}", DL_DIR.to_str().unwrap(), x.title());
|
||||
|
||||
// Create the folder
|
||||
DirBuilder::new().recursive(true).create(&dl_fold).unwrap();
|
||||
|
||||
// Download the episodes
|
||||
eps.iter_mut()
|
||||
.map(|y| -> Result<()> {
|
||||
// Check if its alrdy downloaded
|
||||
if let Some(_) = y.local_uri() {
|
||||
// Not idiomatic but I am still fighting the borrow-checker.
|
||||
if Path::new(y.local_uri().unwrap().to_owned().as_str()).exists() {
|
||||
return Ok(());
|
||||
}
|
||||
y.set_local_uri(None);
|
||||
y.save_changes::<Episode>(connection)?;
|
||||
()
|
||||
};
|
||||
|
||||
// Unreliable and hacky way to extract the file extension from the url.
|
||||
let ext = y.uri().split(".").last().unwrap().to_owned();
|
||||
|
||||
// Construct the download path.
|
||||
let dlpath = format!("{}/{}.{}", dl_fold, y.title().unwrap().to_owned(), ext);
|
||||
// info!("Downloading {:?} into: {}", y.title(), dlpath);
|
||||
download_to(&dlpath, y.uri())?;
|
||||
|
||||
// If download succedes set episode local_uri to dlpath.
|
||||
y.set_local_uri(Some(&dlpath));
|
||||
y.save_changes::<Episode>(connection)?;
|
||||
Ok(())
|
||||
})
|
||||
.fold((), |(), _| ());
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.fold((), |(), _| ());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use reqwest;
|
||||
use rss;
|
||||
use diesel::result;
|
||||
use hammond_data;
|
||||
|
||||
use std::io;
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
ReqError(reqwest::Error);
|
||||
IoError(io::Error);
|
||||
RSSError(rss::Error);
|
||||
DieselResultError(result::Error);
|
||||
HamDBError(hammond_data::errors::Error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate diesel;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
extern crate hammond_data;
|
||||
extern crate hyper;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate reqwest;
|
||||
extern crate rss;
|
||||
|
||||
pub mod downloader;
|
||||
pub mod errors;
|
||||
Reference in New Issue
Block a user