add search and list commands

This commit is contained in:
LordMZTE 2020-12-05 22:20:08 +01:00
parent d0a300e472
commit 6e29fb5fcc
8 changed files with 124 additions and 3 deletions

View file

@ -13,10 +13,13 @@ path = "src/main.rs"
[dependencies]
anyhow = "1.0.34"
clap = "2.33.3"
fuzzy-matcher = "0.3.7"
once_cell = "1.5.2"
opener = "0.4.1"
reqwest = { version = "0.10.9", features = ["stream"] }
serde = { version = "1.0.117", features = ["derive"] }
serde_json = "1.0.60"
structopt = "0.3.21"
term-table = "1.3.0"
term_size = "0.3.2"
tokio = { version = "0.2.23", features = ["macros", "fs", "process"] }

View file

@ -1,4 +1,6 @@
use anyhow::{anyhow, Result};
use serde::Deserialize;
use term_table::{row::Row, table_cell::TableCell};
#[derive(Deserialize)]
pub struct UpResp {
@ -15,3 +17,36 @@ pub struct Category {
pub id: String,
pub name: String,
}
#[derive(Deserialize)]
pub struct Meme {
pub id: String,
pub link: String,
pub path: String,
pub category: String,
pub user: String,
}
impl Meme {
pub fn file_name(&self) -> Result<&str> {
self.path
.split('/')
.last()
.ok_or_else(|| anyhow!("failed to get file name. server response invalid"))
}
}
impl Into<Row<'_>> for &Meme {
fn into(self) -> Row<'static> {
Row::new(vec![
TableCell::new(&self.link),
TableCell::new(&self.category),
TableCell::new(&self.user),
])
}
}
#[derive(Deserialize)]
pub struct MemesResp {
pub memes: Vec<Meme>,
}

17
cli/src/commands/list.rs Normal file
View file

@ -0,0 +1,17 @@
use reqwest::Client;
use anyhow::Result;
use crate::util;
pub async fn run(http: &Client) -> Result<()> {
let memes = util::memes(http).await?;
let mut table = util::list_table();
for m in memes {
table.add_row(m.into());
}
println!("{}", table.render());
Ok(())
}

3
cli/src/commands/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod search;
pub mod up;
pub mod list;

View file

@ -0,0 +1,28 @@
use anyhow::Result;
use reqwest::Client;
use crate::util;
pub async fn run(http: &Client, query: String) -> Result<()> {
let memes = util::memes(http).await?;
let mut matches = vec![];
for meme in memes {
if let Some(score) = fuzzy_matcher::clangd::fuzzy_match(meme.file_name()?, &query) {
matches.push((meme, score));
}
}
matches.sort_by_key(|m| m.1);
let mut table = util::list_table();
for m in matches {
table.add_row(m.0.into());
}
println!("{}", table.render());
Ok(())
}

View file

@ -3,7 +3,7 @@ use reqwest::Client;
use structopt::StructOpt;
mod api;
mod up;
mod commands;
mod util;
#[derive(StructOpt)]
@ -41,6 +41,12 @@ enum Cmd {
#[structopt(help = "lists the available categories")]
Cats,
#[structopt(help = "searches for a meme")]
Search { query: String },
#[structopt(help = "lists all memes")]
List,
}
#[tokio::main]
@ -57,12 +63,14 @@ async fn main() -> Result<()> {
open,
} => {
let name = name.unwrap_or_else(|| file.clone());
up::run(&http, token, file, name, category, open).await?;
commands::up::run(&http, token, file, name, category, open).await?;
},
Cmd::Cats => util::cats(&http)
.await?
.iter()
.for_each(|c| println!("{}", c)),
Cmd::Search { query } => commands::search::run(&http, query).await?,
Cmd::List => commands::list::run(&http).await?,
}
Ok(())

View file

@ -1,11 +1,16 @@
use std::unreachable;
use anyhow::Result;
use once_cell::sync::OnceCell;
use reqwest::Client;
use term_table::{Table, TableBuilder, TableStyle};
use tokio::process::Command;
use crate::api::CatsResp;
use crate::api::{CatsResp, Meme, MemesResp};
// cached api responses
static CATS: OnceCell<Vec<String>> = OnceCell::new();
static MEMES: OnceCell<Vec<Meme>> = OnceCell::new();
pub async fn open_link(url: &str) -> anyhow::Result<()> {
match std::env::var_os("BROWSER") {
@ -31,3 +36,25 @@ pub async fn cats(http: &Client) -> Result<&Vec<String>> {
unreachable!();
}
}
pub async fn memes(http: &Client) -> Result<&Vec<Meme>> {
if MEMES.get().is_none() {
let res = http.get("https://data.tilera.xyz/api/jensmemes/memes")
.send().await?;
let memes = serde_json::from_slice::<MemesResp>(&res.bytes().await?)?;
Ok(MEMES.get_or_init(|| memes.memes))
} else {
unreachable!();
}
}
/// returns an empty table with the correct format settings for lists
pub fn list_table<'a>() -> Table<'a> {
TableBuilder::new()
.style(TableStyle::simple())
.separate_rows(false)
.has_top_boarder(false)
.has_bottom_boarder(false)
.build()
}