snapchat_log_parser/
types.rs

1//! All the types defined by this crate
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use serde_with::rust::string_empty_as_none;
6
7/// Enum for message types
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(untagged)]
10pub enum Message {
11    /// Sent message
12    Sent {
13        /// Username of the person who sent the message
14        #[serde(rename = "To")]
15        to: String,
16        /// Type of the message
17        #[serde(rename = "Media Type")]
18        media_type: MediaType,
19        /// Message creation timestamp
20        #[serde(rename = "Created", with = "crate::timestamp")]
21        created_at: DateTime<Utc>,
22        /// Message text
23        #[serde(rename = "Text", with = "string_empty_as_none")]
24        text: Option<String>,
25    },
26    /// Recieved message
27    Recieved {
28        /// Username of the person who sent the message
29        #[serde(rename = "From")]
30        from: String,
31        /// Type of the message
32        #[serde(rename = "Media Type")]
33        media_type: MediaType,
34        /// Message creation timestamp
35        #[serde(rename = "Created", with = "crate::timestamp")]
36        created_at: DateTime<Utc>,
37        /// Message text
38        #[serde(rename = "Text", with = "string_empty_as_none")]
39        text: Option<String>,
40    }
41}
42
43impl Message {
44    /// Getter for message recipient
45    pub fn recipient(&self) -> String {
46        match self {
47            Message::Recieved { from, ..} => from.to_owned(),
48            Message::Sent { to, .. } => to.to_owned(),
49        }
50    }
51    /// Getter for message media type
52    pub fn media_type(&self) -> MediaType {
53        match self {
54            Self::Recieved { media_type, .. } => media_type.clone(),
55            Self::Sent { media_type, .. } => media_type.clone(),
56        }
57    }
58    /// Getter for message timestamp
59    pub fn created_at(&self) -> DateTime<Utc> {
60        match self {
61            Self::Recieved { created_at, .. } => created_at.clone(),
62            Self::Sent { created_at, .. } => created_at.clone(),
63        }
64    }
65    /// Getter for message text
66    /// # Panics 
67    /// Panics if the media type is not [`MediaType::Text`]
68    pub fn text(&self) -> Option<String> {
69        match self {
70            Self::Recieved { text, .. } => text.clone(),
71            Self::Sent { text, ..} => text.clone()
72        }
73    }
74}
75
76/// A type that contains all data parsed from a chat log file
77#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
78pub struct SnapchatData {
79    /// Recieved chats that have been saved
80    #[serde(rename = "Received Saved Chat History")]
81    pub saved_recieved: Vec<Message>,
82    /// Sent chats that have been saved
83    #[serde(rename = "Sent Saved Chat History")]
84    pub saved_sent: Vec<Message>,
85}
86
87impl SnapchatData {
88    /// Parse a chat log file from a Reader
89    /// # Examples 
90    /// 
91    /// ```no_run
92    /// use std::fs::File;
93    /// use std::io::Read;
94    /// use snapchat_log_parser::types::SnapchatData;
95    /// 
96    /// let mut file = File::open("foo.txt").unwrap();
97    /// let data = SnapchatData::from_reader(file).unwrap();
98    /// ```
99    pub fn from_reader<R: std::io::Read>(rdr: R) -> serde_json::Result<Self> {
100        serde_json::from_reader(rdr)
101    }
102    /// Parse chat logs from a string
103    /// # Examples
104    /// 
105    /// ```
106    /// use snapchat_log_parser::types::SnapchatData;
107    /// 
108    /// // example data
109    /// let json = r#"
110    ///     {
111    ///         "Received Saved Chat History": [{"From": "Felix422", "Media Type": "TEXT", "Created": "2021-01-01 12:00:00 UTC", "Text": "Test Message"}],
112    ///         "Sent Saved Chat History": [{"To": "Felix422", "Media Type": "TEXT", "Created": "2021-01-01 12:00:00 UTC", "Text": "Test Message"}]
113    ///     }
114    ///  "#;
115    /// let data = SnapchatData::from_str(json).unwrap();
116    /// ```
117    pub fn from_str<'a>(s: &'a str) -> serde_json::Result<Self> {
118        serde_json::from_str(s)
119    }
120    /// Gets all messages from the chat with a specific user and sorts them
121    pub fn get_user_chats(self, user: &str) -> Vec<Message> {
122        let predicate = |x: &Message| x.recipient() == user;
123
124        // filter both vectors to only include messages in a specific chat
125        let rec = self.saved_recieved.into_iter().filter(&predicate);
126        let sent = self.saved_sent.into_iter().filter(&predicate);
127
128        // combine iterators
129        let mut combined: Vec<Message> = rec.chain(sent).collect();
130        // sort messages
131        combined.sort_by(|a, b| a.created_at().partial_cmp(&b.created_at()).unwrap());
132        combined
133    }
134}
135
136/// Type of message
137#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq)]
138pub enum MediaType {
139    /// Normal text message
140    #[serde(rename = "TEXT")]
141    Text,
142    /// Image
143    #[serde(rename = "MEDIA")]
144    Media,
145    /// Sticker
146    #[serde(rename = "STICKER")]
147    Sticker,
148    #[serde(rename = "SHARE")]
149    Share,
150    #[serde(rename = "NOTE")]
151    Note,
152    /// Shared Location
153    #[serde(rename = "LOCATION")]
154    Location,
155}