2021-06-30 16:30:05 +00:00
|
|
|
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();
|
2021-07-24 19:07:36 +00:00
|
|
|
let mut count = 0;
|
2021-06-30 16:30:05 +00:00
|
|
|
|
2021-07-24 19:07:36 +00:00
|
|
|
println!("\n\nResults:\n");
|
2021-06-30 16:30:05 +00:00
|
|
|
|
|
|
|
// 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, ®ex) && (include_retoots || status.reblog.is_none()) {
|
2021-07-24 19:07:36 +00:00
|
|
|
print_status(&status, verbose);
|
|
|
|
count += 1;
|
2021-06-30 16:30:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If there's a limit of results, check it and exit
|
|
|
|
if let Some(max) = max_statuses {
|
2021-07-24 19:07:36 +00:00
|
|
|
if count >= max {
|
2021-06-30 16:30:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-24 19:07:36 +00:00
|
|
|
println!("Found {} results", count);
|
2021-06-30 16:30:05 +00:00
|
|
|
|
2021-07-24 19:07:36 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_status(status: &Status, verbose: bool) {
|
|
|
|
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 {
|
2021-06-30 16:30:05 +00:00
|
|
|
println!("Url: {}", url);
|
|
|
|
}
|
2021-07-24 19:07:36 +00:00
|
|
|
} else if let Some(url) = &status.url {
|
|
|
|
println!("Url: {}", url);
|
|
|
|
}
|
2021-06-30 16:30:05 +00:00
|
|
|
|
2021-07-24 19:07:36 +00:00
|
|
|
// 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);
|
2021-06-30 16:30:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-24 19:07:36 +00:00
|
|
|
println!();
|
2021-06-30 16:30:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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())
|
|
|
|
}
|