use std::{collections::HashMap, str::FromStr}; use http::Uri; use crate::error::{AppError, AppResult}; #[derive(Clone)] pub(crate) enum ArtKind { Twitter, Safebooru, } impl FromStr for ArtKind { type Err = AppError; fn from_str(s: &str) -> Result { match s { "twitter.com" => Ok(Self::Twitter), "safebooru.org" => Ok(Self::Safebooru), _ => Err("not support website".into()), } } } #[derive(Clone)] pub(crate) struct Art { pub(crate) url: Uri, pub(crate) kind: ArtKind, } impl FromStr for Art { type Err = AppError; fn from_str(s: &str) -> Result { let url: Uri = s.parse()?; let kind: ArtKind = url.authority().unwrap().host().parse()?; Ok(Self { url, kind }) } } pub(crate) struct Data { // actual arts art: Vec, art_indices: HashMap, } impl Data { pub(crate) fn parse(data: &str) -> AppResult { let mut this = Self { art: Default::default(), art_indices: Default::default(), }; for entry in data.lines() { let art: Art = entry.parse()?; this.art_indices.insert(art.url.clone(), this.art.len()); this.art.push(art); } Ok(this) } pub(crate) fn pick_random_art(&self) -> &Art { let no = fastrand::usize(0..self.art.len()); &self.art[no] } pub(crate) fn reload(&mut self, data: &str) -> AppResult<()> { for entry in data.lines() { let art: Art = entry.parse()?; if !self.art_indices.contains_key(&art.url) { self.art_indices.insert(art.url.clone(), self.art.len()); self.art.push(art); } } Ok(()) } }