A better Rust ATProto crate
1use clap::Parser; 2use jacquard::CowStr; 3use jacquard::api::app_bsky::actor::{AdultContentPref, PreferencesItem}; 4use jacquard::client::AgentSessionExt; 5use jacquard::client::vec_update::PreferencesUpdate; 6use jacquard::client::{Agent, FileAuthStore}; 7use jacquard::oauth::client::OAuthClient; 8use jacquard::oauth::loopback::LoopbackConfig; 9 10#[derive(Parser, Debug)] 11#[command(author, version, about = "Update Bluesky preferences")] 12struct Args { 13 /// Handle (e.g., alice.bsky.social), DID, or PDS URL 14 input: CowStr<'static>, 15 16 /// Enable adult content 17 #[arg(long)] 18 enable_adult_content: bool, 19 20 /// Path to auth store file (will be created if missing) 21 #[arg(long, default_value = "/tmp/jacquard-oauth-session.json")] 22 store: String, 23} 24 25#[tokio::main] 26async fn main() -> miette::Result<()> { 27 let args = Args::parse(); 28 29 let oauth = OAuthClient::with_default_config(FileAuthStore::new(&args.store)); 30 let session = oauth 31 .login_with_local_server(args.input, Default::default(), LoopbackConfig::default()) 32 .await?; 33 34 let agent: Agent<_> = Agent::from(session); 35 36 // Create the adult content preference 37 let adult_pref = AdultContentPref { 38 enabled: args.enable_adult_content, 39 extra_data: Default::default(), 40 }; 41 42 // Update preferences using update_vec_item 43 // This will replace existing AdultContentPref or add it if not present 44 agent 45 .update_vec_item::<PreferencesUpdate>(PreferencesItem::AdultContentPref(Box::new( 46 adult_pref, 47 ))) 48 .await?; 49 50 println!( 51 "✓ Updated adult content preference: {}", 52 if args.enable_adult_content { 53 "enabled" 54 } else { 55 "disabled" 56 } 57 ); 58 59 Ok(()) 60}