implement almost everything

main
annieversary 2021-06-30 18:30:05 +02:00
commit 7d0a809bd6
4 changed files with 2326 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
.DS_Store
mastodon-data.toml

2139
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "tootre"
version = "0.1.0"
edition = "2018"
[dependencies]
clap = "2.33.3"
elefren = { version = "0.22.0", features = ["toml"] }
home = "0.5.3"
regex = "1.5.4"

174
src/main.rs Normal file
View File

@ -0,0 +1,174 @@
use std::error::Error;
use elefren::entities::status::Status;
use elefren::helpers::cli;
use elefren::helpers::toml;
use elefren::prelude::*;
use clap::{App, Arg};
use regex::Regex;
// TODO Put data.toml file path in an env var
fn main() -> Result<(), Box<dyn Error>> {
let matches = App::new("tootre")
.version("0.1")
.author("annieversary")
.about("grep through own toots")
.arg(
Arg::with_name("regex")
.short("r")
.long("regex")
.value_name("REGEX")
.required(true)
.help("Regex to use for matching toots"),
)
.arg(
Arg::with_name("max")
.short("m")
.long("max")
.value_name("MAX")
.help("Max number of toots to find"),
)
.arg(
Arg::with_name("boosts")
.short("b")
.long("boosts")
.help("Includes boosts in the search"),
)
.arg(
Arg::with_name("v")
.short("v")
.long("verbose")
.help("Sets the level of verbosity"),
)
.get_matches();
let max = matches
.value_of("max")
.map(|val| val.parse::<usize>().ok())
.flatten();
let verbose = matches.is_present("v");
let include_retoots = matches.is_present("boosts");
if let Some(regex) = matches.value_of("regex") {
run(regex, max, verbose, include_retoots)
} else {
panic!("Regex was not provided");
}
}
/// Returns path for config
fn get_path() -> std::path::PathBuf {
if let Some(mut home) = home::home_dir() {
home.push(".tootre.toml");
home
} else {
".tootre.toml".into()
}
}
fn run(
regex: &str,
max_statuses: Option<usize>,
verbose: bool,
include_retoots: bool,
) -> Result<(), Box<dyn Error>> {
let client = if let Ok(data) = toml::from_file(get_path()) {
Mastodon::from(data)
} else {
register()?
};
if verbose {
println!("Getting statuses...");
}
// Get statuses for own account
let acc = client.verify_credentials()?;
let statuses = client.statuses(&acc.id, None)?;
let regex = Regex::new(regex).unwrap();
let mut results = Vec::new();
if verbose {
println!("Searching...");
}
// Search through statuses
for status in statuses.items_iter() {
// Add it to results if it matches and it isn't a retoot
// or if it matches and isn't a retoot
if status_matches(&status, &regex) && (include_retoots || status.reblog.is_none()) {
results.push(status);
}
// If there's a limit of results, check it and exit
if let Some(max) = max_statuses {
if results.len() >= max {
break;
}
}
}
println!("\n\nResults:\n");
// Print results
for status in &results {
if !status.spoiler_text.is_empty() {
println!("CW: {}", status.spoiler_text);
}
println!("Content: {}", status.content);
// Print actual url if it's a retoot
if let Some(retoot) = &status.reblog {
if let Some(url) = &retoot.url {
println!("Url: {}", url);
}
} else if let Some(url) = &status.url {
println!("Url: {}", url);
}
// Print some extra info
if verbose {
println!("Created at: {}", status.created_at);
if let Some(retoot) = &status.reblog {
println!("Is retoot: yes ({})", retoot.account.acct);
} else {
// We don't want to print these if it's a retoot
println!("Favs: {}", status.favourites_count);
println!("Retoots: {}", status.reblogs_count);
}
}
println!();
}
println!("Found {} results", results.len());
Ok(())
}
fn status_matches(status: &Status, regex: &Regex) -> bool {
regex.is_match(&status.content) || regex.is_match(&status.spoiler_text)
}
fn register() -> Result<Mastodon, Box<dyn Error>> {
println!("You are not registered, registering...");
let url = read_line("Enter instance url (eg: https://mastodon.social):")?;
let registration = Registration::new(url).client_name("tootre").build()?;
let mastodon = cli::authenticate(registration)?;
// Save app data for using on the next run.
toml::to_file(&mastodon, get_path())?;
Ok(mastodon)
}
pub fn read_line(message: &str) -> Result<String, Box<dyn Error>> {
println!("{}", message);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
Ok(input.trim().to_string())
}