use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
use tui::widgets::TableState;
use crate::{counts::Counts, utils::write_to_file, Error, Result};
mod creator;
mod post;
pub use creator::{Creator, Creators};
pub use post::{Post, Posts};
static DOWNLOAD_POSTS: AtomicBool = AtomicBool::new(false);
pub fn download_posts() -> bool {
DOWNLOAD_POSTS.load(Ordering::Relaxed)
}
pub fn set_download_posts(val: bool) {
DOWNLOAD_POSTS.store(val, Ordering::SeqCst)
}
pub async fn dl_posts(url: &str) -> Result<PostResponses> {
let https = hyper_tls::HttpsConnector::new();
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
let response = client.get(hyper::Uri::from_str(url)?).await?;
let body = hyper::body::to_bytes(response.into_body()).await?;
#[cfg(feature = "debug_endpoints")]
write_to_file("posts.json", &body)?;
serde_json::from_slice::<PostResponses>(&body).map_err(|err| err.into())
}
pub fn is_image(url: &str) -> bool {
url.ends_with(".bmp")
|| url.ends_with(".gif")
|| url.ends_with(".jpg")
|| url.ends_with(".jpeg")
|| url.ends_with(".png")
|| url.ends_with(".webp")
}
pub fn image_name(url: &str) -> Result<&str> {
let uri = url.parse::<http::Uri>()?;
let path = uri.path();
if path.ends_with(".bmp") {
Ok("tmp.bmp")
} else if path.ends_with(".gif") {
Ok("tmp.gif")
} else if path.ends_with(".jpg") || path.ends_with(".jpeg") {
Ok("tmp.jpeg")
} else if path.ends_with(".png") {
Ok("tmp.png")
} else if path.ends_with(".webp") {
Ok("tmp.webp")
} else {
Err(Error::Image("unsupported image type".into()))
}
}
pub async fn dl_image(url: &str, file_name: &str) -> Result<()> {
let https = hyper_tls::HttpsConnector::new();
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
let response = client.get(hyper::Uri::from_str(url)?).await?;
let body = hyper::body::to_bytes(response.into_body()).await?;
write_to_file(file_name, &body)?;
Ok(())
}
pub fn load_posts(file_name: &str) -> Result<PostResponses> {
use std::io::Read;
let mut file = std::fs::File::open(file_name)?;
let mut res = String::new();
file.read_to_string(&mut res)?;
serde_json::from_str::<PostResponses>(res.as_str()).map_err(|err| err.into())
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct PostResponse {
pub post: Post,
pub creator: Creator,
pub counts: Counts,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct PostResponses {
pub posts: Vec<PostResponse>,
}
pub struct PostResponseTable {
pub items: Vec<PostResponse>,
pub state: TableState,
}
impl PostResponseTable {
pub fn new(items: Vec<PostResponse>) -> Self {
Self {
items,
state: TableState::default(),
}
}
pub fn items(&self) -> &[PostResponse] {
self.items.as_ref()
}
pub fn state(&self) -> &TableState {
&self.state
}
pub fn state_mut(&mut self) -> &mut TableState {
&mut self.state
}
pub fn current(&self) -> Option<&PostResponse> {
if let Some(i) = self.state.selected() {
self.items.get(i)
} else {
None
}
}
pub fn current_mut(&mut self) -> Option<&mut PostResponse> {
if let Some(i) = self.state.selected() {
self.items.get_mut(i)
} else {
None
}
}
pub fn deselect(&mut self) {
self.state.select(None);
}
pub fn next(&mut self) {
let len = self.items.len();
let i = self.state.selected().map(|i| (i + 1) % len).unwrap_or(0);
self.state.select(Some(i));
}
pub fn previous(&mut self) {
let len = self.items.len();
let last = len.saturating_sub(1);
let i = self
.state
.selected()
.map(|i| if i == 0 { last } else { i.saturating_sub(1) })
.unwrap_or(last);
self.state.select(Some(i));
}
}
impl From<Vec<PostResponse>> for PostResponseTable {
fn from(val: Vec<PostResponse>) -> Self {
Self::new(val)
}
}
impl From<PostResponses> for PostResponseTable {
fn from(val: PostResponses) -> Self {
Self::new(val.posts)
}
}
impl AsRef<PostResponse> for PostResponse {
fn as_ref(&self) -> &Self {
self
}
}
impl AsMut<PostResponse> for PostResponse {
fn as_mut(&mut self) -> &mut Self {
self
}
}