use dirs;
use itertools::Itertools;
use reqwest::{self, Client};
use std::collections::HashMap;
use std::fs::{self, OpenOptions};
use std::io::{self, Write};
use FontError;
const API_KEY: &str = "AIzaSyDpvpba_5RvJSvmXEJS7gZDezDaMlVTo4c";
lazy_static! {
static ref URL_ALPHA: String = {
format!(
"https://www.googleapis.com/webfonts/v1/webfonts?sort=alpha&key={}",
API_KEY
)
};
}
lazy_static! {
static ref URL_DATE: String = {
format!(
"https://www.googleapis.com/webfonts/v1/webfonts?sort=date&key={}",
API_KEY
)
};
}
lazy_static! {
static ref URL_POPULARITY: String = {
format!(
"https://www.googleapis.com/webfonts/v1/webfonts?sort=popularity&key={}",
API_KEY
)
};
}
lazy_static! {
static ref URL_TRENDING: String = {
format!(
"https://www.googleapis.com/webfonts/v1/webfonts?sort=trending&key={}",
API_KEY
)
};
}
#[derive(Deserialize)]
pub struct FontsList {
pub kind: String,
pub items: Vec<Font>,
}
impl FontsList {
pub fn download<W>(&self, writer: &mut W, family: &str) -> Result<(), FontError>
where
W: Write,
{
let client = Client::new();
let path = dirs::font_cache().ok_or(FontError::FontDirectory)?;
dirs::recursively_create(&path)?;
let font = self.get_family(family).ok_or(FontError::FontNotFound)?;
for (variant, uri) in &font.files {
let path = dirs::get_font_path(&path, family, &variant, &uri);
let _ = writer.write(format!("Installing '{:?}'\n", path).as_bytes());
let mut data = client.get(uri.as_str()).send()?;
let mut file = OpenOptions::new().create(true).write(true).open(&path)?;
io::copy(&mut data, &mut file)?;
}
Ok(())
}
pub fn remove<W>(&self, writer: &mut W, family: &str) -> Result<(), FontError>
where
W: Write,
{
let path = dirs::font_cache().ok_or(FontError::FontDirectory)?;
let font = self.get_family(family).ok_or(FontError::FontNotFound)?;
for (variant, uri) in &font.files {
let path = dirs::get_font_path(&path, family, &variant, &uri);
let _ = writer.write(format!("Removing '{:?}'\n", path).as_bytes());
if let Err(why) = fs::remove_file(&path) {
let msg = format!("Unable to remove '{:?}': {}\n", path, why);
let _ = writer.write(msg.as_bytes());
}
}
Ok(())
}
pub fn get_family<'a>(&'a self, family: &str) -> Option<&'a Font> {
self.items.iter().find(|f| f.family.as_str() == family)
}
pub fn get_categories(&self) -> Vec<String> {
self.items
.iter()
.map(|f| f.category.as_str())
.unique()
.map(String::from)
.collect()
}
}
#[derive(Deserialize)]
pub struct Font {
pub kind: String,
pub family: String,
pub category: String,
pub variants: Vec<String>,
pub subsets: Vec<String>,
pub version: String,
pub modified: Option<String>,
pub files: HashMap<String, String>,
}
pub enum Sorting {
Alphabetical,
DateAdded,
Popular,
Trending,
}
pub fn obtain(sort_by: Sorting) -> reqwest::Result<FontsList> {
let url: &'static str = match sort_by {
Sorting::Alphabetical => URL_ALPHA.as_str(),
Sorting::DateAdded => URL_DATE.as_str(),
Sorting::Popular => URL_POPULARITY.as_str(),
Sorting::Trending => URL_TRENDING.as_str(),
};
reqwest::get(url)?.json()
}