aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--src/commands/fav.rs4
-rw-r--r--src/commands/thread.rs2
-rw-r--r--src/commands/twete.rs14
-rw-r--r--src/commands/view.rs2
-rw-r--r--src/display/mod.rs28
-rw-r--r--src/main.rs1
-rw-r--r--src/tw/mod.rs200
-rw-r--r--src/tw/tweet.rs5
9 files changed, 180 insertions, 78 deletions
diff --git a/Cargo.toml b/Cargo.toml
index b37cf52..b1f3677 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,6 @@ hyper-tls = "*"
"futures" = "*"
"serde_json" = "*"
"chan" = "*"
-chrono = "0.4"
+chrono = { version = "0.4", features = ["serde"] }
serde = "*"
serde_derive = "*"
diff --git a/src/commands/fav.rs b/src/commands/fav.rs
index 0bee8ce..5e5f2a2 100644
--- a/src/commands/fav.rs
+++ b/src/commands/fav.rs
@@ -21,7 +21,7 @@ fn unfav(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, di
let maybe_id = TweetId::parse(line.to_owned());
match maybe_id {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
let result = match tweeter.current_profile() {
Some(user_profile) => queryer.do_api_post(&format!("{}?id={}", UNFAV_TWEET_URL, twete.id), &tweeter.app_key, &user_profile.creds),
None => Err("No logged in user to unfav from".to_owned())
@@ -53,7 +53,7 @@ fn fav(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, disp
match maybe_id {
Ok(twid) => {
// tweeter.to_twitter_tweet_id(twid)...
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
let result = match tweeter.current_profile() {
Some(user_profile) => queryer.do_api_post(&format!("{}?id={}", FAV_TWEET_URL, twete.id), &tweeter.app_key, &user_profile.creds),
None => Err("No logged in user to fav from".to_owned())
diff --git a/src/commands/thread.rs b/src/commands/thread.rs
index 302e641..f82fb13 100644
--- a/src/commands/thread.rs
+++ b/src/commands/thread.rs
@@ -38,7 +38,7 @@ fn remember(line: String, tweeter: &mut tw::TwitterCache, _queryer: &mut Queryer
let maybe_id = TweetId::parse(line.to_owned());
match maybe_id {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) {
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) {
tweeter.set_thread(name.to_string(), twete.internal_id);
display_info.status(format!("Ok! Recorded {:?} as thread {}", twid, name));
} else {
diff --git a/src/commands/twete.rs b/src/commands/twete.rs
index ac4bbeb..ebf3c3d 100644
--- a/src/commands/twete.rs
+++ b/src/commands/twete.rs
@@ -22,7 +22,7 @@ fn del(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, disp
match TweetId::parse(line.clone()) {
Ok(twid) => {
// TODO this really converts twid to a TweetId::Twitter
- if let Some(twitter_id) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.id.to_owned()) {
+ if let Some(twitter_id) = tweeter.retrieve_tweet(&twid).map(|x| x.id.to_owned()) {
let result = match tweeter.current_profile() {
Some(user_profile) => queryer.do_api_post(&format!("{}/{}.json", DEL_TWEET_URL, twitter_id), &tweeter.app_key, &user_profile.creds),
None => Err("No logged in user to delete as".to_owned())
@@ -100,7 +100,7 @@ fn thread(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, d
let maybe_id = TweetId::parse(id_str.to_owned());
match maybe_id {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
let handle = &tweeter.retrieve_user(&twete.author_id).unwrap().handle.to_owned();
// TODO: definitely breaks if you change your handle right now
if handle == &user_profile.user.handle {
@@ -152,13 +152,13 @@ fn rep(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, disp
let maybe_id = TweetId::parse(id_str.to_owned());
match maybe_id {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
// get handles to reply to...
let author_handle = tweeter.retrieve_user(&twete.author_id).unwrap().handle.to_owned();
let mut ats: Vec<String> = twete.get_mentions(); //std::collections::HashSet::new();
ats.remove_item(&author_handle);
ats.insert(0, author_handle);
- if let Some(rt_tweet) = twete.rt_tweet.and_then(|id| tweeter.retrieve_tweet(&TweetId::Twitter(id), display_info)).map(|x| x.clone()) {
+ if let Some(rt_tweet) = twete.rt_tweet.and_then(|id| tweeter.retrieve_tweet(&TweetId::Twitter(id))).map(|x| x.clone()) {
let rt_author_handle = tweeter.retrieve_user(&rt_tweet.author_id).unwrap().handle.to_owned();
ats.remove_item(&rt_author_handle);
ats.insert(1, rt_author_handle);
@@ -191,7 +191,7 @@ fn rep(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, disp
}
pub fn send_reply(text: String, twid: TweetId, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, user_creds: tw::Credential, display_info: &mut DisplayInfo) {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
let substituted = ::url_encode(&text);
let result = match tweeter.current_profile() {
Some(user_profile) => {
@@ -226,7 +226,7 @@ fn quote(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer, di
let maybe_id = TweetId::parse(id_str.to_owned());
match maybe_id {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
+ if let Some(twete) = tweeter.retrieve_tweet(&twid).map(|x| x.clone()) { // TODO: no clone when this stops taking &mut self
let substituted = ::url_encode(reply);
let attachment_url = ::url_encode(
&format!(
@@ -281,7 +281,7 @@ fn retwete(line: String, tweeter: &mut tw::TwitterCache, queryer: &mut Queryer,
match TweetId::parse(line.clone()) {
Ok(twid) => {
// TODO this really converts twid to a TweetId::Twitter
- if let Some(twitter_id) = tweeter.retrieve_tweet(&twid, display_info).map(|x| x.id.to_owned()) {
+ if let Some(twitter_id) = tweeter.retrieve_tweet(&twid).map(|x| x.id.to_owned()) {
let result = match tweeter.current_profile() {
Some(user_profile) => {
queryer.do_api_post(&format!("{}/{}.json", RT_TWEET_URL, twitter_id), &tweeter.app_key, &user_profile.creds)
diff --git a/src/commands/view.rs b/src/commands/view.rs
index 41dd9b3..18ba871 100644
--- a/src/commands/view.rs
+++ b/src/commands/view.rs
@@ -19,7 +19,7 @@ pub static VIEW: Command = Command {
fn view(line: String, tweeter: &mut tw::TwitterCache, _queryer: &mut Queryer, display_info: &mut DisplayInfo) {
match TweetId::parse(line) {
Ok(twid) => {
- if let Some(twete) = tweeter.retrieve_tweet(&twid, display_info) {
+ if let Some(twete) = tweeter.retrieve_tweet(&twid) {
display_info.recv(display::Infos::TweetWithContext(
TweetId::Twitter(twete.id.to_owned()),
format!("link: https://twitter.com/i/web/status/{}", twete.id)
diff --git a/src/display/mod.rs b/src/display/mod.rs
index 3e9d725..8d1f725 100644
--- a/src/display/mod.rs
+++ b/src/display/mod.rs
@@ -345,9 +345,10 @@ pub fn paint(tweeter: &::tw::TwitterCache, display_info: &mut DisplayInfo) -> Re
// draw input prompt
let mut i = 0;
let log_size = 4;
- let last_elem = display_info.log.len().saturating_sub(log_size);
+ let last_tail_log = display_info.log.len().saturating_sub(display_info.infos_seek as usize);
+ let first_tail_log = last_tail_log.saturating_sub(log_size);
{
- let to_show = display_info.log[last_elem..].iter().rev();
+ let to_show = display_info.log[first_tail_log..last_tail_log].iter().rev();
for line in to_show {
print!("{}{}{}/{}: {}", cursor::Goto(1, height - i), clear::CurrentLine, display_info.log.len() - 1 - i as usize, display_info.log.len() - 1, line);
i = i + 1;
@@ -435,7 +436,7 @@ pub fn paint(tweeter: &::tw::TwitterCache, display_info: &mut DisplayInfo) -> Re
let wrapped = if total_length <= 1024 {
into_display_lines(pre_split, width)
} else {
- vec!["This tweet discarded for your convenience".to_owned()]
+ vec![format!("This tweet discarded for your convenience: (id: {})", id)]
};
wrapped.into_iter().rev().collect()
}
@@ -551,7 +552,7 @@ impl Render for tw::events::Event {
}
tw::events::Event::Deleted { user_id, twete_id } => {
if let Some(handle) = tweeter.retrieve_user(&user_id).map(|x| &x.handle).map(|x| x.clone()) {
- if let Some(_tweet) = tweeter.retrieve_tweet(&TweetId::Twitter(twete_id.to_owned()), display_info).map(|x| x.clone()) {
+ if let Some(_tweet) = tweeter.retrieve_tweet(&TweetId::Twitter(twete_id.to_owned())).map(|x| x.clone()) {
result.push(format!("-------------DELETED------------------"));
result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter, display_info, Some(width)));
result.push(format!("-------------DELETED------------------"));
@@ -621,7 +622,7 @@ fn pad_lines(lines: Vec<String>, padding: &str) -> Vec<String> {
pub fn render_twete(twete_id: &TweetId, tweeter: &tw::TwitterCache, display_info: &mut DisplayInfo, width: Option<u16>) -> Vec<String> {
let mut lines = render_twete_no_recurse(twete_id, tweeter, display_info, width);
- match tweeter.retrieve_tweet(twete_id, display_info).map(|x| x.clone()) {
+ match tweeter.retrieve_tweet(twete_id).map(|x| x.clone()) {
Some(twete) => {
if let Some(ref qt_id) = twete.quoted_tweet_id {
lines.extend(pad_lines(render_twete_no_recurse(&TweetId::Twitter(qt_id.to_owned()), tweeter, display_info, width.map(|x| x - 4)), " "));
@@ -636,7 +637,7 @@ pub fn render_twete_no_recurse(twete_id: &TweetId, tweeter: &tw::TwitterCache, d
// ~~ reactive ~~ layout if the terminal isn't wide enough? for now just wrap to passed width
let mut result = Vec::new();
let id_color = color::Fg(color::Rgb(180, 80, 40));
- match tweeter.retrieve_tweet(twete_id, display_info).map(|x| x.clone()) {
+ match tweeter.retrieve_tweet(twete_id).map(|x| x.clone()) {
Some(twete) => {
// if we got the tweet, the API gave us the user too
let user = tweeter.retrieve_user(&twete.author_id).map(|x| x.clone()).unwrap();
@@ -657,27 +658,26 @@ pub fn render_twete_no_recurse(twete_id: &TweetId, tweeter: &tw::TwitterCache, d
.clone()
.map(|rt_id| (TweetId::Twitter(rt_id), Some(TweetId::Twitter(twete.id.to_owned())))).unwrap_or((TweetId::Twitter(twete.id.to_owned()), None));
// retrieve_* taking mut tweeter REALLY messes stuff up.
- let tweet = tweeter.retrieve_tweet(&tweet_id, display_info).unwrap().clone();
+ let tweet = tweeter.retrieve_tweet(&tweet_id).unwrap().clone();
+ let tweet_id = tweeter.display_id_for_tweet(&tweet);
let tweet_author = tweeter.retrieve_user(&tweet.author_id).unwrap().clone();
// now we've unfurled it so id is the original tweet either way, maybe_rt_id is the id
// of the retweeter tweet if it's there
- let mut id_string = format!("{}id {}", id_color, tweet.internal_id);
+ let mut id_string = format!("{}id {}", id_color, tweet_id);
let mut author_string = format!("{}{}{} ({}@{}{})", color_for(&tweet_author.handle), tweet_author.name, color::Fg(color::Reset), color_for(&tweet_author.handle), tweet_author.handle, color::Fg(color::Reset));
if let Some(reply_id) = tweet.reply_to_tweet.clone() {
- let reply_tweet_id = match tweeter.retrieve_tweet(&TweetId::Twitter(reply_id.to_owned()), display_info) {
- Some(reply_tweet) => TweetId::Bare(reply_tweet.internal_id),
- None => TweetId::Twitter(reply_id)
- };
+ let reply_tweet_id = tweeter.display_id_for_tweet_id(&TweetId::Twitter(reply_id.to_owned()));
id_string.push_str(&format!(" reply to {}", reply_tweet_id))
}
if let Some(rt_id) = maybe_rt_id {
- let rt = tweeter.retrieve_tweet(&rt_id, display_info).unwrap().clone();
+ let rt = tweeter.retrieve_tweet(&rt_id).unwrap().clone();
+ let rt_id = tweeter.display_id_for_tweet(&rt);
let rt_author = tweeter.retrieve_user(&rt.author_id).unwrap().clone();
- id_string.push_str(&format!(" (rt id {})", rt.internal_id));
+ id_string.push_str(&format!(" (rt id {})", rt_id));
author_string.push_str(&format!(" via {}{}{} ({}@{}{}) RT", color_for(&rt_author.handle), rt_author.name, color::Fg(color::Reset), color_for(&rt_author.handle), rt_author.handle, color::Fg(color::Reset)));
}
diff --git a/src/main.rs b/src/main.rs
index 73ad9d9..d8ef738 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
#![feature(vec_remove_item)]
extern crate serde_json;
+extern crate chrono;
extern crate termion;
extern crate termios;
diff --git a/src/tw/mod.rs b/src/tw/mod.rs
index 629a6c7..737286d 100644
--- a/src/tw/mod.rs
+++ b/src/tw/mod.rs
@@ -131,17 +131,21 @@ pub struct TwitterCache {
// twitter::num // twiter tweet id num
struct IdConversions {
// maps a day to the base id for tweets off that day.
- id_per_date: HashMap<String, u64>,
- id_to_tweet_id: HashMap<u64, String>
+ id_to_tweet_id: HashMap<u64, String>,
// twitter id to id is satisfied by looking up the twitter id in tweeter.tweets and getting
// .inner_id
+ // YYYYMMDD : day_id : inner_tweet_id
+ tweets_by_date: HashMap<String, HashMap<u64, u64>>,
+ // YYYYMMDD : inner_tweet_id : day_id
+ tweets_by_date_and_tweet_id: HashMap<String, HashMap<u64, u64>>
}
impl Default for IdConversions {
fn default() -> Self {
IdConversions {
- id_per_date: HashMap::new(),
- id_to_tweet_id: HashMap::new()
+ id_to_tweet_id: HashMap::new(),
+ tweets_by_date: HashMap::new(),
+ tweets_by_date_and_tweet_id: HashMap::new()
}
}
}
@@ -180,6 +184,7 @@ mod tests {
fn tweet_id_parse_test() {
assert_eq!(TweetId::parse("12345".to_string()), Ok(TweetId::Today(12345)));
assert_eq!(TweetId::parse("20170403:12345".to_string()), Ok(TweetId::Dated("20170403".to_string(), 12345)));
+ assert_eq!(TweetId::parse("20170403:12345".to_string()), Ok(TweetId::Dated("20170403".to_string(), 12345)));
assert_eq!(TweetId::parse(":12345".to_string()), Ok(TweetId::Bare(12345)));
assert_eq!(TweetId::parse("twitter:12345".to_string()), Ok(TweetId::Twitter("12345".to_string())));
assert_eq!(TweetId::parse("twitter:asdf".to_string()), Ok(TweetId::Twitter("asdf".to_string())));
@@ -192,6 +197,57 @@ mod tests {
assert_eq!(TweetId::parse(":a34".to_string()), Err("invalid digit found in string".to_owned()));
assert_eq!(TweetId::parse("asdf:34".to_string()), Err("Unrecognized id string: asdf:34".to_owned()));
}
+
+ #[test]
+ fn test_tweet_retrieval() {
+ let today = Local::now();
+ let yesterday = today - chrono::Duration::days(1);
+ let tweets = vec![
+ Tweet {
+ id: "manual_tweet_1".to_owned(),
+ author_id: "author_1".to_owned(),
+ text: "this is a test".to_owned(),
+ created_at: "1234 not real lol".to_owned(),
+ recieved_at: yesterday,
+ urls: HashMap::new(),
+ quoted_tweet_id: None,
+ rt_tweet: None,
+ reply_to_tweet: None,
+ internal_id: 0
+ },
+ Tweet {
+ id: "manual_tweet_2".to_owned(),
+ author_id: "author_1".to_owned(),
+ text: "this is a test".to_owned(),
+ created_at: "1234 not real lol".to_owned(),
+ recieved_at: today,
+ urls: HashMap::new(),
+ quoted_tweet_id: None,
+ rt_tweet: None,
+ reply_to_tweet: None,
+ internal_id: 0
+ }
+ ];
+
+ let mut tweeter = TwitterCache::new();
+
+ for tweet in &tweets {
+ tweeter.number_and_insert_tweet(tweet.to_owned());
+ }
+
+ assert_eq!(
+ tweeter.retrieve_tweet(&TweetId::Twitter("manual_tweet_1".to_owned())).map(|x| x.id.to_owned()),
+ Some(tweets[0].clone()).map(|x| x.id)
+ );
+ assert_eq!(
+ tweeter.retrieve_tweet(&TweetId::Today(0)).map(|x| x.id.to_owned()),
+ Some(tweets[1].clone()).map(|x| x.id)
+ );
+ assert_eq!(
+ tweeter.retrieve_tweet(&TweetId::Dated(format!("{:04}{:02}{:02}", yesterday.year(), yesterday.month(), yesterday.day()), 0)).map(|x| x.id.to_owned()),
+ Some(tweets[0].clone()).map(|x| x.id)
+ );
+ }
}
impl TweetId {
@@ -230,18 +286,55 @@ impl IdConversions {
//
// except in the TweetId::Twitter case we TweetId -> Option<Tweet> -> Option<u64> ... to ->
// Option<Tweet> in the future?
- fn to_inner_id(&self, tweeter: &TwitterCache, twid: TweetId, display_info: &mut DisplayInfo) -> Option<u64> {
+ fn to_twitter_id(&self, twid: TweetId) -> Option<String> {
match twid {
TweetId::Today(num) => {
- let first_for_today: u64 = 0;
- Some(first_for_today + num)
+ let now = Local::now();
+ let now_date_str = format!("{:04}{:02}{:02}", now.year(), now.month(), now.day());
+ let tweet_id = self.tweets_by_date.get(&now_date_str).and_then(|x| x.get(&num));
+ tweet_id.and_then(|x| self.id_to_tweet_id.get(x)).map(|x| x.to_owned())
},
TweetId::Dated(date, num) => {
- let first_for_date: u64 = 0;
- Some(first_for_date + num)
+ let tweet_id = self.tweets_by_date.get(&date).and_then(|x| x.get(&num));
+ tweet_id.and_then(|x| self.id_to_tweet_id.get(x)).map(|x| x.to_owned())
},
- TweetId::Bare(num) => Some(num),
- twid @ TweetId::Twitter(_) => tweeter.retrieve_tweet(&twid, display_info).map(|x| x.internal_id)
+ TweetId::Bare(num) => self.id_to_tweet_id.get(&num).map(|x| x.to_owned()),
+ TweetId::Twitter(id) => Some(id)
+ }
+ }
+
+ fn to_display_id(&self, twid: &TweetId, tweeter: &TwitterCache) -> TweetId {
+ match twid {
+ id @ &TweetId::Today(_) => id.to_owned(),
+ id @ &TweetId::Dated(_, _) => {
+ tweeter.retrieve_tweet(id).map(|x| TweetId::Bare(x.internal_id)).unwrap_or(id.to_owned())
+ },
+ id @ &TweetId::Bare(_) => {
+ tweeter.retrieve_tweet(id).and_then(|tweet| {
+ let now = Local::now();
+ let tweet_date = tweet.recieved_at.with_timezone(&now.timezone());
+ if now.year() == tweet_date.year() && now.month() == tweet_date.month() && now.day() == tweet_date.day() {
+ let date_string = format!("{:04}{:02}{:02}", tweet.recieved_at.year(), tweet.recieved_at.month(), tweet.recieved_at.day());
+ let today_id = self.tweets_by_date_and_tweet_id.get(&date_string).and_then(|m| m.get(&tweet.internal_id));
+ today_id.map(|x| TweetId::Today(*x))
+ } else {
+ None
+ }
+ }).unwrap_or(id.to_owned())
+ },
+ id @ &TweetId::Twitter(_) => {
+ tweeter.retrieve_tweet(id).and_then(|tweet| {
+ let now = Local::now();
+ let tweet_date = tweet.recieved_at.with_timezone(&now.timezone());
+ if now.year() == tweet_date.year() && now.month() == tweet_date.month() && now.day() == tweet_date.day() {
+ let date_string = format!("{:04}{:02}{:02}", tweet.recieved_at.year(), tweet.recieved_at.month(), tweet.recieved_at.day());
+ let today_id = self.tweets_by_date_and_tweet_id.get(&date_string).and_then(|m| m.get(&tweet.internal_id));
+ today_id.map(|x| TweetId::Today(*x))
+ } else {
+ None
+ }
+ }).unwrap_or(id.to_owned())
+ }
}
}
}
@@ -500,10 +593,44 @@ impl TwitterCache {
if tw.internal_id == 0 {
tw.internal_id = (self.tweets.len() as u64) + 1;
self.id_conversions.id_to_tweet_id.insert(tw.internal_id, tw.id.to_owned());
+ let local_recv_time = tw.recieved_at.with_timezone(&Local::now().timezone());
+ let tweet_date = format!("{:04}{:02}{:02}", local_recv_time.year(), local_recv_time.month(), local_recv_time.day());
+ if !self.id_conversions.tweets_by_date.contains_key(&tweet_date) {
+ self.id_conversions.tweets_by_date.insert(tweet_date.clone(), HashMap::new());
+ }
+ if !self.id_conversions.tweets_by_date_and_tweet_id.contains_key(&tweet_date) {
+ self.id_conversions.tweets_by_date_and_tweet_id.insert(tweet_date.clone(), HashMap::new());
+ }
+
+ let date_map: &mut HashMap<u64, u64> = self.id_conversions.tweets_by_date.get_mut(&tweet_date).unwrap();
+ let next_idx = date_map.len() as u64;
+ date_map.insert(next_idx, tw.internal_id);
+
+ let date_map: &mut HashMap<u64, u64> = self.id_conversions.tweets_by_date_and_tweet_id.get_mut(&tweet_date).unwrap();
+ let next_idx = date_map.len() as u64;
+ date_map.insert(tw.internal_id, next_idx);
+
self.tweets.insert(tw.id.to_owned(), tw);
}
}
}
+ pub fn display_id_for_tweet(&self, tweet: &Tweet) -> TweetId {
+ let now = Local::now();
+ let tweet_date = tweet.recieved_at.with_timezone(&now.timezone());
+ let bare_id = TweetId::Bare(tweet.internal_id);
+ let maybe_dated_id = if now.year() == tweet_date.year() && now.month() == tweet_date.month() && now.day() == tweet_date.day() {
+ let date_string = format!("{:04}{:02}{:02}", tweet.recieved_at.year(), tweet.recieved_at.month(), tweet.recieved_at.day());
+ let today_id = self.id_conversions.tweets_by_date_and_tweet_id.get(&date_string).and_then(|m| m.get(&tweet.internal_id));
+ today_id.map(|x| TweetId::Today(*x))
+ } else {
+ None
+ };
+
+ maybe_dated_id.unwrap_or(bare_id)
+ }
+ pub fn display_id_for_tweet_id(&self, twid: &TweetId) -> TweetId {
+ self.id_conversions.to_display_id(twid, self)
+ }
pub fn load_cache(display_info: &mut DisplayInfo) -> TwitterCache {
if Path::new(TwitterCache::PROFILE_CACHE).is_file() {
let mut buf = vec![];
@@ -641,54 +768,23 @@ impl TwitterCache {
/* nothing else to care about now, i think? */
}
}
- pub fn retrieve_tweet(&self, tweet_id: &TweetId, display_info: &mut DisplayInfo) -> Option<&Tweet> {
- match tweet_id {
- &TweetId::Bare(ref id) => {
- let maybe_tweet_id = self.id_conversions.id_to_tweet_id.get(id);
- match maybe_tweet_id {
- Some(id) => self.tweets.get(id),
- None => None
- }
- },
- &TweetId::Today(ref id) => {
- let inner_id = self.id_conversions.id_to_tweet_id.get(id);
- display_info.status("Retrieving tweets with dated IDs is not yet supported.".to_string());
- None
- },
- &TweetId::Dated(ref date, ref id) => {
- display_info.status("Retrieving tweets with dated IDs is not yet supported.".to_string());
- None
- },
- &TweetId::Twitter(ref id) => self.tweets.get(id)
- }
+ pub fn retrieve_tweet(&self, tweet_id: &TweetId) -> Option<&Tweet> {
+ let maybe_tweet_id = self.id_conversions.to_twitter_id(tweet_id.to_owned());
+ maybe_tweet_id.and_then(|id| self.tweets.get(&id))
}
pub fn retrieve_user(&self, user_id: &String) -> Option<&User> {
self.users.get(user_id)
}
pub fn fetch_tweet(&mut self, tweet_id: &TweetId, mut queryer: &mut ::Queryer, display_info: &mut DisplayInfo) -> Option<&Tweet> {
- match tweet_id {
- &TweetId::Bare(ref id) => {
- // we can do nothing but just try to get it
- self.retrieve_tweet(tweet_id, display_info)
- }
- &TweetId::Today(ref id) => {
- // we can do nothing but just try to get it
- self.retrieve_tweet(tweet_id, display_info)
- },
- &TweetId::Dated(ref date, ref id) => {
- // we can do nothing but just try to get it
- self.retrieve_tweet(tweet_id, display_info)
- },
- &TweetId::Twitter(ref id) => {
- if !self.tweets.contains_key(id) {
- match self.look_up_tweet(id, &mut queryer) {
- Ok(json) => self.cache_api_tweet(json),
- Err(e) => display_info.status(format!("Unable to retrieve tweet {}:\n{}", id, e))
- };
- }
- self.retrieve_tweet(tweet_id, display_info)
+ if let &TweetId::Twitter(ref id) = tweet_id {
+ if !self.tweets.contains_key(id) {
+ match self.look_up_tweet(id, &mut queryer) {
+ Ok(json) => self.cache_api_tweet(json),
+ Err(e) => display_info.status(format!("Unable to retrieve tweet {}:\n{}", id, e))
+ };
}
}
+ self.retrieve_tweet(tweet_id)
}
pub fn fetch_user(&mut self, user_id: &String, mut queryer: &mut ::Queryer, display_info: &mut DisplayInfo) -> Option<&User> {
if !self.users.contains_key(user_id) {
diff --git a/src/tw/tweet.rs b/src/tw/tweet.rs
index 38b838d..2ca32c3 100644
--- a/src/tw/tweet.rs
+++ b/src/tw/tweet.rs
@@ -1,5 +1,7 @@
extern crate serde_json;
+use chrono::prelude::*;
+
use std::collections::HashMap;
use tw::user::User;
@@ -10,6 +12,8 @@ pub struct Tweet {
pub author_id: String,
pub text: String,
pub created_at: String, // lol
+ #[serde(default = "Utc::now")]
+ pub recieved_at: DateTime<Utc>,
#[serde(skip_serializing_if="HashMap::is_empty")]
#[serde(default = "HashMap::default")]
pub urls: HashMap<String, String>,
@@ -84,6 +88,7 @@ impl Tweet {
author_id: author_id.to_owned(),
text: text,
created_at: created_at.to_owned(),
+ recieved_at: Utc::now(),
urls: url_map,
quoted_tweet_id: json_map.get("quoted_status_id_str")
.and_then(|x| x.as_str())