twitter_archive/structs/
lists_member.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/lists-member.js
6//!
7//! ## Warnings
8//!
9//! - `.[].<KEY_NAME>.LocationHistory` data structure is subject to future changes
10//!
11//! ## Example file reader
12//!
13//! ```no_build
14//! use std::io::Read;
15//! use std::{fs, path};
16//! use zip::read::ZipArchive;
17//!
18//! use twitter_archive::structs::lists_member;
19//!
20//! fn main() {
21//!     let input_file = "~/Downloads/twitter-archive.zip";
22//!
23//!     let file_descriptor = fs::File::open(input_file).expect("Unable to read --input-file");
24//!     let mut zip_archive = ZipArchive::new(file_descriptor).unwrap();
25//!     let mut zip_file = zip_archive.by_name("data/lists-member.js").unwrap();
26//!     let mut buff = String::new();
27//!     zip_file.read_to_string(&mut buff).unwrap();
28//!
29//!     let json = buff.replacen("window.YTD.lists_member.part0 = ", "", 1);
30//!     let data: Vec<lists_member::UserListInfoObject> = serde_json::from_str(&json).expect("Unable to parse");
31//!
32//!     for (index, object) in data.iter().enumerate() {
33//!         /* Do stuff with each `niDeviceResponse` entry */
34//!         println!("Lists member index: {index}");
35//!         println!("URL: {}", object.user_list_info.url);
36//!     }
37//! }
38//! ```
39//!
40//! ## Example `twitter-<DATE>-<UID>.zip:data/lists-member.js` content
41//!
42//! ```javascript
43//! window.YTD.lists_member.part0 = [
44//!   {
45//!     "userListInfo" : {
46//!       "url" : "https://twitter.com/M16229Myers/lists/1696117177802211514"
47//!     }
48//!   },
49//!   {
50//!     "userListInfo" : {
51//!       "url" : "https://twitter.com/R0oTk1t/lists/1572592337959944198"
52//!     }
53//!   }
54//! ]
55//! ```
56
57use derive_more::Display;
58use serde::{Deserialize, Serialize};
59
60/// ## Example
61///
62/// ```
63/// use twitter_archive::structs::lists_member::UserListInfoObject;
64///
65/// let json = r#"{
66///   "userListInfo": {
67///     "url": "https://twitter.com/R0oTk1t/lists/1572592337959944198"
68///   }
69/// }"#;
70///
71/// let data: UserListInfoObject = serde_json::from_str(&json).unwrap();
72///
73/// // De-serialized properties
74/// assert_eq!(data.user_list_info.url, "https://twitter.com/R0oTk1t/lists/1572592337959944198");
75///
76/// // Re-serialize is equivalent to original data
77/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
78/// ```
79#[derive(Deserialize, Serialize, Debug, Clone, Display)]
80#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
81#[serde(rename_all = "camelCase")]
82pub struct UserListInfoObject {
83	/// ## Example JSON data
84	///
85	/// ```json
86	/// {
87	///   "userListInfo": {
88	///     "url": "https://twitter.com/R0oTk1t/lists/1572592337959944198"
89	///   }
90	/// }
91	/// ```
92	pub user_list_info: UserListInfo,
93}
94
95/// ## Example
96///
97/// ```
98/// use twitter_archive::structs::lists_member::UserListInfo;
99///
100/// let json = r#"{
101///   "url": "https://twitter.com/R0oTk1t/lists/1572592337959944198"
102/// }"#;
103///
104/// let data: UserListInfo = serde_json::from_str(&json).unwrap();
105///
106/// // De-serialized properties
107/// assert_eq!(data.url, "https://twitter.com/R0oTk1t/lists/1572592337959944198");
108///
109/// // Re-serialize is equivalent to original data
110/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
111/// ```
112#[derive(Deserialize, Serialize, Debug, Clone, Display)]
113#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
114pub struct UserListInfo {
115	/// ## Example JSON data
116	///
117	/// ```json
118	/// { "url": "https://twitter.com/R0oTk1t/lists/1572592337959944198" }
119	/// ```
120	pub url: String,
121}