fur_cli/renderer/
utils.rs

1use std::fs;
2use std::path::Path;
3use serde_json::Value;
4use chrono::{DateTime, FixedOffset, Local};
5
6use crate::frs::avatars::resolve_avatar;
7
8/// Struct holding normalized message info
9#[allow(dead_code)]
10pub struct MessageInfo {
11    pub date_str: String,
12    pub time_str: String,
13    pub name: String,
14    pub emoji: String,
15    pub text: String,
16    pub markdown: Option<String>,
17    pub attachment: Option<String>, 
18    #[allow(dead_code)]
19    pub children: Vec<String>,
20    pub branches: Vec<Vec<String>>,
21}
22
23
24
25/// Load and normalize a message JSON
26pub fn load_message(fur_dir: &Path, msg_id: &str, avatars: &Value) -> Option<MessageInfo> {
27    let msg_path = fur_dir.join("messages").join(format!("{}.json", msg_id));
28    let msg_content = fs::read_to_string(&msg_path).ok()?;
29    let msg_json: Value = serde_json::from_str(&msg_content).ok()?;
30
31    // Timestamp
32    let raw_time = msg_json["timestamp"].as_str().unwrap_or("???");
33    let (date_str, time_str) = if let Ok(dt) = raw_time.parse::<DateTime<FixedOffset>>() {
34        let local_dt = dt.with_timezone(&Local);
35        (local_dt.format("%Y-%m-%d").to_string(), local_dt.format("%H:%M:%S").to_string())
36    } else {
37        (raw_time.to_string(), "".to_string())
38    };
39
40    // Avatar
41    let avatar_key = msg_json["avatar"].as_str().unwrap_or("???");
42    let (name, emoji) = resolve_avatar(avatars, avatar_key);
43
44    // Text & markdown
45    let text = msg_json["text"].as_str().unwrap_or("<no content>").to_string();
46    let markdown = msg_json["markdown"].as_str().map(|s| s.to_string());
47
48    // Children
49    let children = msg_json["children"]
50        .as_array()
51        .map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())
52        .unwrap_or_else(Vec::new);
53
54    // Branches
55    let branches = msg_json["branches"]
56        .as_array()
57        .map(|outer| {
58            outer.iter()
59                .filter_map(|block| {
60                    block.as_array().map(|arr| {
61                        arr.iter()
62                            .filter_map(|v| v.as_str().map(|s| s.to_string()))
63                            .collect::<Vec<_>>()
64                    })
65                })
66                .collect::<Vec<_>>()
67        })
68        .unwrap_or_else(Vec::new);
69
70    let attachment = msg_json["attachment"].as_str().map(|s| s.to_string());
71
72    Some(MessageInfo {
73        date_str,
74        time_str,
75        name,
76        emoji,
77        text,
78        markdown,
79        attachment,
80        children,
81        branches,
82    })
83}