twitter_archive/structs/direct_message_headers.rs
1#!/usr/bin/env rust
2
3//! Tweeter archives as of 2023-08-31 have private data found under;
4//!
5//! twitter-<DATE>-<UID>.zip:data/direct-message-headers.js
6//!
7//! ## Example file reader
8//!
9//! ```no_build
10//! use std::io::Read;
11//! use std::{fs, path};
12//! use zip::read::ZipArchive;
13//!
14//! use twitter_archive::structs::direct_message_headers;
15//!
16//! fn main() {
17//! let input_file = "~/Downloads/twitter-archive.zip";
18//!
19//! let file_descriptor = fs::File::open(input_file).expect("Unable to read --input-file");
20//! let mut zip_archive = ZipArchive::new(file_descriptor).unwrap();
21//! let mut zip_file = zip_archive.by_name("data/direct-message-headers.js").unwrap();
22//! let mut buff = String::new();
23//! zip_file.read_to_string(&mut buff).unwrap();
24//!
25//! let json = buff.replacen("window.YTD.direct_message_headers.part0 = ", "", 1);
26//! let data: Vec<direct_message_headers::DmConversationObject> = serde_json::from_str(&json).expect("Unable to parse");
27//!
28//! for (index_header, object_header) in data.iter().enumerate() {
29//! /* Do stuff with each `DmConversationObject` entry */
30//! println!("Conversation header index: {index_header}");
31//! println!("Conversation ID: {}", object_header.dm_conversation.conversation_id);
32//! for (index_message, object_message) in object_header.dm_conversation.messages.iter().enumerate() {
33//! /* Do stuff with each `object_message` entry */
34//! println!("Message header index: {index_message}");
35//! println!("Created at: {}", object_message.message_create.created_at);
36//! println!("Message ID: {}", object_message.message_create.id);
37//! println!("Sender ID: {}", object_message.message_create.sender_id);
38//! println!("Recipient ID: {}", object_message.message_create.recipient_id);
39//! }
40//! }
41//! }
42//! ```
43//!
44//! ## Example `twitter-<DATE>-<UID>.zip:data/direct-message-headers.js` content
45//!
46//! ```javascript
47//! window.YTD.direct_message_headers.part0 = [
48//! ]
49//! ```
50
51use chrono::{DateTime, Utc};
52use derive_more::Display;
53use serde::{Deserialize, Serialize};
54
55use crate::convert;
56
57/// ## Example
58///
59/// ```
60/// use chrono::{DateTime, NaiveDateTime, Utc};
61///
62/// use twitter_archive::convert::date_time_iso_8601;
63///
64/// use twitter_archive::structs::direct_message_headers::DmConversationObject;
65///
66/// let created_at_string = "2023-08-12T17:10:37.000Z";
67/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
68/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
69///
70/// let json = format!(r#"{{
71/// "dmConversation": {{
72/// "conversationId": "1111-2222",
73/// "messages": [
74/// {{
75/// "messageCreate": {{
76/// "id": "1111111111111111111",
77/// "senderId": "2222",
78/// "recipientId": "1111",
79/// "createdAt": "{created_at_string}"
80/// }}
81/// }}
82/// ]
83/// }}
84/// }}"#);
85///
86/// let data: DmConversationObject = serde_json::from_str(&json).unwrap();
87///
88/// // De-serialized properties
89/// assert_eq!(data.dm_conversation.conversation_id, "1111-2222");
90///
91/// assert_eq!(data.dm_conversation.messages.len(), 1);
92/// assert_eq!(data.dm_conversation.messages[0].message_create.id, "1111111111111111111");
93/// assert_eq!(data.dm_conversation.messages[0].message_create.sender_id, "2222");
94/// assert_eq!(data.dm_conversation.messages[0].message_create.recipient_id, "1111");
95/// assert_eq!(data.dm_conversation.messages[0].message_create.created_at, created_at_date_time);
96///
97/// // Re-serialize is equivalent to original data without pretty printing
98/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
99/// ```
100#[derive(Deserialize, Serialize, Debug, Clone, Display)]
101#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
102#[serde(rename_all = "camelCase")]
103pub struct DmConversationObject {
104 /// ## Example JSON data
105 ///
106 /// ```json
107 /// {
108 /// "dmConversation": {
109 /// "conversationId": "1111-2222",
110 /// "messages": [
111 /// {
112 /// "messageCreate": {
113 /// "id": "1111111111111111111",
114 /// "senderId": "2222",
115 /// "recipientId": "1111",
116 /// "createdAt": "2023-08-12T17:10:37.000Z"
117 /// }
118 /// }
119 /// ]
120 /// }
121 /// }
122 /// ```
123 pub dm_conversation: DmConversation,
124}
125
126/// ## Example
127///
128/// ```
129/// use chrono::{DateTime, NaiveDateTime, Utc};
130///
131/// use twitter_archive::convert::date_time_iso_8601;
132///
133/// use twitter_archive::structs::direct_message_headers::DmConversation;
134///
135/// let created_at_string = "2023-08-12T17:10:37.000Z";
136/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
137/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
138///
139/// let json = format!(r#"{{
140/// "conversationId": "1111-2222",
141/// "messages": [
142/// {{
143/// "messageCreate": {{
144/// "id": "1111111111111111111",
145/// "senderId": "2222",
146/// "recipientId": "1111",
147/// "createdAt": "{created_at_string}"
148/// }}
149/// }}
150/// ]
151/// }}"#);
152///
153/// let data: DmConversation = serde_json::from_str(&json).unwrap();
154///
155/// // De-serialized properties
156/// assert_eq!(data.conversation_id, "1111-2222");
157///
158/// assert_eq!(data.messages.len(), 1);
159/// assert_eq!(data.messages[0].message_create.id, "1111111111111111111");
160/// assert_eq!(data.messages[0].message_create.sender_id, "2222");
161/// assert_eq!(data.messages[0].message_create.recipient_id, "1111");
162/// assert_eq!(data.messages[0].message_create.created_at, created_at_date_time);
163///
164/// // Re-serialize is equivalent to original data without pretty printing
165/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
166/// ```
167#[derive(Deserialize, Serialize, Debug, Clone, Display)]
168#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
169#[serde(rename_all = "camelCase")]
170pub struct DmConversation {
171 /// ## Example JSON data
172 ///
173 /// ```json
174 /// { "conversationId": "1111-2222" }
175 /// ```
176 pub conversation_id: String,
177
178 /// ## Example JSON data
179 ///
180 /// ```json
181 /// {
182 /// "messages": [
183 /// {
184 /// "messageCreate": {
185 /// "id": "1111111111111111111",
186 /// "senderId": "2222",
187 /// "recipientId": "1111",
188 /// "createdAt": "2023-08-12T17:10:37.000Z"
189 /// }
190 /// }
191 /// ]
192 /// }
193 /// ```
194 pub messages: Vec<MessageCreateObject>,
195}
196
197/// ## Example
198///
199/// ```
200/// use chrono::{DateTime, NaiveDateTime, Utc};
201///
202/// use twitter_archive::convert::date_time_iso_8601;
203///
204/// use twitter_archive::structs::direct_message_headers::MessageCreateObject;
205///
206/// let created_at_string = "2023-08-12T17:10:37.000Z";
207/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
208/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
209///
210/// let json = format!(r#"{{
211/// "messageCreate": {{
212/// "id": "1111111111111111111",
213/// "senderId": "2222",
214/// "recipientId": "1111",
215/// "createdAt": "{created_at_string}"
216/// }}
217/// }}"#);
218///
219/// let data: MessageCreateObject = serde_json::from_str(&json).unwrap();
220///
221/// // De-serialized properties
222/// assert_eq!(data.message_create.id, "1111111111111111111");
223/// assert_eq!(data.message_create.sender_id, "2222");
224/// assert_eq!(data.message_create.recipient_id, "1111");
225/// assert_eq!(data.message_create.created_at, created_at_date_time);
226///
227/// // Re-serialize is equivalent to original data without pretty printing
228/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
229/// ```
230#[derive(Deserialize, Serialize, Debug, Clone, Display)]
231#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
232#[serde(rename_all = "camelCase")]
233pub struct MessageCreateObject {
234 /// ## Example JSON data
235 ///
236 /// ```json
237 /// {
238 /// "messageCreate": {
239 /// "id": "1111111111111111111",
240 /// "senderId": "2222",
241 /// "recipientId": "1111",
242 /// "createdAt": "2023-08-12T17:10:37.000Z"
243 /// }
244 /// }
245 /// ```
246 pub message_create: MessageCreate,
247}
248
249/// ## Example
250///
251/// ```
252/// use chrono::{DateTime, NaiveDateTime, Utc};
253///
254/// use twitter_archive::convert::date_time_iso_8601;
255///
256/// use twitter_archive::structs::direct_message_headers::MessageCreate;
257///
258/// let created_at_string = "2023-08-12T17:10:37.000Z";
259/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
260/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
261///
262/// let json = format!(r#"{{
263/// "id": "1111111111111111111",
264/// "senderId": "2222",
265/// "recipientId": "1111",
266/// "createdAt": "{created_at_string}"
267/// }}"#);
268///
269/// let data: MessageCreate = serde_json::from_str(&json).unwrap();
270///
271/// // De-serialized properties
272/// assert_eq!(data.id, "1111111111111111111");
273/// assert_eq!(data.sender_id, "2222");
274/// assert_eq!(data.recipient_id, "1111");
275/// assert_eq!(data.created_at, created_at_date_time);
276///
277/// // Re-serialize is equivalent to original data without pretty printing
278/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
279/// ```
280#[derive(Deserialize, Serialize, Debug, Clone, Display)]
281#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
282#[serde(rename_all = "camelCase")]
283pub struct MessageCreate {
284 /// ## Example JSON data
285 ///
286 /// ```json
287 /// { "id": "1111111111111111111" }
288 /// ```
289 pub id: String,
290
291 /// ID of user sending message
292 ///
293 /// URL formats;
294 ///
295 /// - Desktop: `https://twitter.com/i/user/{sender_id}`
296 ///
297 /// > Note; does **not** work if not logged-in. Thanks be to Mr. Musk !-D
298 ///
299 /// ## Example JSON data
300 ///
301 /// ```json
302 /// { "senderId": "2222" }
303 /// ```
304 pub sender_id: String,
305
306 /// ID of user receiving message
307 ///
308 /// URL formats;
309 ///
310 /// - Desktop: `https://twitter.com/i/user/{recipient_id}`
311 ///
312 /// > Note; does **not** work if not logged-in. Thanks be to Mr. Musk !-D
313 ///
314 /// ## Example JSON data
315 ///
316 /// ```json
317 /// { "recipientId": "1111" }
318 /// ```
319 pub recipient_id: String,
320
321 /// Date time stamp when DM was created
322 ///
323 /// ## Example JSON data
324 ///
325 /// ```json
326 /// { "createdAt": "2023-08-12T17:10:37.000Z" }
327 /// ```
328 #[serde(with = "convert::date_time_iso_8601")]
329 pub created_at: DateTime<Utc>,
330}