forked from xenua/fedi-frq-friend
xenua
2 years ago
commit
0de46b3ce3
5 changed files with 2013 additions and 0 deletions
@ -0,0 +1,17 @@ |
|||||||
|
[package] |
||||||
|
name = "fedi-frq-friend" |
||||||
|
version = "0.1.0" |
||||||
|
edition = "2021" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
futures-util = "0.3.28" |
||||||
|
knuffel = "3.0.0" |
||||||
|
mastodon-async = { version = "1.2.1", features = ["toml", "mt"] } |
||||||
|
tokio = { version = "1.27.0", features = ["full"] } |
||||||
|
|
||||||
|
|
||||||
|
[[bin]] |
||||||
|
name = "f3" |
||||||
|
path = "src/main.rs" |
@ -0,0 +1,2 @@ |
|||||||
|
status-text "this is the automated follow request message from fedi-frq-friend. i haven't set the message in the config yet!" |
||||||
|
with-cw "automated follow request pm" // optional |
@ -0,0 +1,110 @@ |
|||||||
|
use futures_util::TryStreamExt; |
||||||
|
use mastodon_async::entities::notification::NotificationType; |
||||||
|
use mastodon_async::helpers::cli::authenticate; |
||||||
|
use mastodon_async::helpers::toml; |
||||||
|
use mastodon_async::prelude::*; |
||||||
|
use mastodon_async::Result as MResult; |
||||||
|
|
||||||
|
use std::fs::File; |
||||||
|
use std::io::{self, Write}; |
||||||
|
|
||||||
|
const DEFAULT_CONFIG: &'static str = include_str!("default_config.kdl"); |
||||||
|
|
||||||
|
#[derive(knuffel::Decode, Debug, Clone)] |
||||||
|
struct Config { |
||||||
|
#[knuffel(child, unwrap(argument))] |
||||||
|
status_text: String, |
||||||
|
#[knuffel(child, unwrap(argument))] |
||||||
|
with_cw: Option<String>, |
||||||
|
} |
||||||
|
|
||||||
|
async fn get_mastodon() -> MResult<Mastodon> { |
||||||
|
if let Ok(data) = toml::from_file("fedi-data.toml") { |
||||||
|
Ok(Mastodon::from(data)) |
||||||
|
} else { |
||||||
|
log_in().await |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async fn log_in() -> MResult<Mastodon> { |
||||||
|
println!("fedi-data.toml is missing, doing initial setup:"); |
||||||
|
print!("Enter your instance url (e.g. botsin.space): "); |
||||||
|
io::stdout().flush()?; |
||||||
|
|
||||||
|
let mut instance = String::new(); |
||||||
|
io::stdin().read_line(&mut instance)?; |
||||||
|
|
||||||
|
if !(instance.starts_with("http://") || instance.starts_with("https://")) { |
||||||
|
instance = format!("https://{instance}"); |
||||||
|
} |
||||||
|
|
||||||
|
let registration = Registration::new(instance.trim()) |
||||||
|
.client_name("frq-friend") |
||||||
|
.scopes(Scopes::all()) |
||||||
|
.build() |
||||||
|
.await?; |
||||||
|
let mastodon = authenticate(registration).await?; |
||||||
|
|
||||||
|
toml::to_file(&mastodon.data, "fedi-data.toml")?; |
||||||
|
|
||||||
|
Ok(mastodon) |
||||||
|
} |
||||||
|
|
||||||
|
async fn do_the_thing() -> MResult<()> { |
||||||
|
let config_string = std::fs::read_to_string("config.kdl").unwrap_or_else(|_| { |
||||||
|
File::create("config.kdl") |
||||||
|
.and_then(|mut v| v.write_all(DEFAULT_CONFIG.as_bytes())) |
||||||
|
.expect("Unable to write default to config.kdl; is the working dir writable?"); |
||||||
|
println!("created example config.kdl. you probably want to change the text in there"); |
||||||
|
DEFAULT_CONFIG.to_string() |
||||||
|
}); |
||||||
|
let config: Config = |
||||||
|
knuffel::parse("config.kdl", &config_string).expect("Error parsing config.kdl"); |
||||||
|
|
||||||
|
let mastodon = get_mastodon().await?; |
||||||
|
let stream = mastodon.stream_notifications().await?; |
||||||
|
println!("listening for events\n--------------------"); |
||||||
|
stream |
||||||
|
.try_for_each(|(event, client)| { |
||||||
|
let cfg = config.clone(); |
||||||
|
async move { |
||||||
|
match event { |
||||||
|
Event::Notification { |
||||||
|
0: |
||||||
|
Notification { |
||||||
|
notification_type: NotificationType::FollowRequest, |
||||||
|
account, |
||||||
|
.. |
||||||
|
}, |
||||||
|
} => { |
||||||
|
println!( |
||||||
|
"got a follow request from {} (@{})", |
||||||
|
account.display_name, account.acct |
||||||
|
); |
||||||
|
|
||||||
|
let mut builder = StatusBuilder::new(); |
||||||
|
builder |
||||||
|
.status(format!("@{}\n{}", account.acct, cfg.status_text)) |
||||||
|
.visibility(Visibility::Direct); |
||||||
|
|
||||||
|
if let Some(cw) = cfg.with_cw { |
||||||
|
builder.sensitive(true).spoiler_text(cw); |
||||||
|
} |
||||||
|
|
||||||
|
let status = builder.build()?; |
||||||
|
|
||||||
|
client.new_status(status).await?; |
||||||
|
} |
||||||
|
_ => (), |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
}) |
||||||
|
.await?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
#[tokio::main] |
||||||
|
async fn main() -> MResult<()> { |
||||||
|
do_the_thing().await |
||||||
|
} |
Loading…
Reference in new issue