xmaster 1.6.3

Enterprise-grade X/Twitter CLI — post, reply, like, retweet, DM, search, and more
use crate::cli::parse_tweet_id;
use crate::context::AppContext;
use crate::errors::XmasterError;
use crate::intel::store::IntelStore;
use crate::output::{self, OutputFormat, Tableable};
use crate::providers::xapi::XApi;
use serde::Serialize;
use std::sync::Arc;

#[derive(Serialize)]
struct PostDisplay {
    id: String,
    author: String,
    text: String,
    likes: u64,
    retweets: u64,
    replies: u64,
    impressions: u64,
    bookmarks: u64,
    #[serde(skip_serializing_if = "Option::is_none")]
    date: Option<String>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    media_urls: Vec<String>,
}

impl Tableable for PostDisplay {
    fn to_table(&self) -> comfy_table::Table {
        let mut table = comfy_table::Table::new();
        table.set_header(vec!["Field", "Value"]);
        table.add_row(vec!["ID", &self.id]);
        table.add_row(vec!["Author", &self.author]);
        table.add_row(vec!["Text", &self.text]);
        table.add_row(vec!["Likes", &self.likes.to_string()]);
        table.add_row(vec!["Retweets", &self.retweets.to_string()]);
        table.add_row(vec!["Replies", &self.replies.to_string()]);
        table.add_row(vec!["Impressions", &self.impressions.to_string()]);
        table.add_row(vec!["Bookmarks", &self.bookmarks.to_string()]);
        if let Some(ref date) = self.date {
            table.add_row(vec!["Date", date]);
        }
        for url in &self.media_urls {
            table.add_row(vec!["Media", url]);
        }
        table
    }
}

pub async fn execute(
    ctx: Arc<AppContext>,
    format: OutputFormat,
    id: &str,
) -> Result<(), XmasterError> {
    let api = XApi::new(ctx.clone());
    let tweet_id = parse_tweet_id(id);
    let tweet = api.get_tweet(&tweet_id).await?;
    if let Ok(store) = IntelStore::open() {
        let _ = store.record_discovered_post("read", &tweet);
    }

    let metrics = tweet.public_metrics.as_ref();
    let display = PostDisplay {
        id: tweet.id,
        author: tweet
            .author_username
            .map(|u| format!("@{u}"))
            .unwrap_or_else(|| tweet.author_id.unwrap_or_default()),
        text: tweet.text,
        likes: metrics.map(|m| m.like_count).unwrap_or(0),
        retweets: metrics.map(|m| m.retweet_count).unwrap_or(0),
        replies: metrics.map(|m| m.reply_count).unwrap_or(0),
        impressions: metrics.map(|m| m.impression_count).unwrap_or(0),
        bookmarks: metrics.map(|m| m.bookmark_count).unwrap_or(0),
        date: tweet.created_at,
        media_urls: tweet.media_urls,
    };
    output::render(format, &display, None);
    Ok(())
}