add search and list commands
This commit is contained in:
parent
d0a300e472
commit
6e29fb5fcc
|
@ -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"] }
|
||||
|
|
|
@ -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
17
cli/src/commands/list.rs
Normal 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
3
cli/src/commands/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod search;
|
||||
pub mod up;
|
||||
pub mod list;
|
28
cli/src/commands/search.rs
Normal file
28
cli/src/commands/search.rs
Normal 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(())
|
||||
}
|
|
@ -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(())
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue