diff --git a/TODO b/TODO index b552800..6445f07 100644 --- a/TODO +++ b/TODO @@ -15,4 +15,3 @@ bugs: * Direct Messages have no names, only screen names (may not be fixable without considerable tweaks to python-twitter) -* New posts sometimes inherit 'in reply to' text of old posts diff --git a/apithreads.py b/apithreads.py index c674984..4658cdc 100644 --- a/apithreads.py +++ b/apithreads.py @@ -57,38 +57,47 @@ class GetTweets(ApiThread): def run(self): - with self.api.lock: - try: - # username/Home entries need to load the appropriate Home feed - if self.list_name == self.username + '/Home': + try: + # username/Home entries need to load the appropriate Home feed + if self.list_name == self.username + '/Home': + with self.api.lock: statuses = self.api.GetHomeTimeline(count=self.num_entries) - # For @username, check if it is one of our usernames, or - # just needs to be searched on - elif self.list_name == '@' + self.username: + # For @username, check if it is one of our usernames, or + # just needs to be searched on + elif self.list_name == '@' + self.username: + with self.api.lock: statuses = self.api.GetMentions(count=self.num_entries) - elif re.match('@', self.list_name): - statuses = results_to_statuses(self.api.Search(self.list_name, rpp=self.num_entries)) + elif re.match('@', self.list_name): + with self.api.lock: + results = self.api.Search(self.list_name, rpp=self.num_entries) + statuses = results_to_statuses(results, self.api) - # Direct Messages should match like /Home, above - elif self.list_name == self.username + '/Direct Messages': - statuses = dms_to_statuses(self.api.GetDirectMessages()) - - # User lookups go straight to the user - elif re.match(r'user: ', self.list_name): + # Direct Messages should match like /Home, above + elif self.list_name == self.username + '/Direct Messages': + with self.api.lock: + dms = self.api.GetDirectMessages() + statuses = dms_to_statuses(dms) + + # User lookups go straight to the user + elif re.match(r'user: ', self.list_name): + with self.api.lock: statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', self.list_name), count=self.num_entries) - # Lists load the appropriate list from the appropriate account - elif re.match(r'list: ', self.list_name): - real_list = re.sub(r'list: .*/(.*)', r'\1', self.list_name) + # Lists load the appropriate list from the appropriate account + elif re.match(r'list: ', self.list_name): + real_list = re.sub(r'list: .*/(.*)', r'\1', self.list_name) + with self.api.lock: statuses = self.api.GetListStatuses(real_list, per_page=self.num_entries) - # Everything else is a straight search - else: - statuses = results_to_statuses(self.api.Search(self.list_name, rpp=self.num_entries)) + # Everything else is a straight search + else: + with self.api.lock: + results = self.api.Search(self.list_name, rpp=self.num_entries) + statuses = results_to_statuses(results, self.api) - except (HTTPError, URLError): - statuses = None + except (HTTPError, URLError): + statuses = None # For each user id present, populate the AvCache with an image if statuses: @@ -206,6 +215,11 @@ class GetUserLists(ApiThread): class SigProxy(gtk.Alignment): + """ + This little class exists just so that we can have a gtk class in our + threads that can emit signals. That way, we can communicate data back to + the gtk interface easily. + """ def __init__(self): gtk.Alignment.__init__(self) @@ -238,11 +252,16 @@ class Status(): self.in_reply_to_status_id = None -# To keep things simple elsewhere and improve code reuse -# we'll build a list of home-cooked Status objects out of results. -# Why is this even necessary? -# Why can't we have more consistency out of the Twitter API? -def results_to_statuses(results): +def results_to_statuses(results, api): + """ + Since the REST API and the Search API return different result types, this + function converts Search API Results into custom-baked Status objects that + mimic those returned by the REST API. + + To get the 'in reply to' data, it has to grab the individual tweet for any + status that has a to_user_id field set. This can slow things down a lot. + fixme: add an option to disable this for speed... + """ statuses = [] for result in results.results: status = Status() @@ -261,11 +280,25 @@ def results_to_statuses(results): created_split = re.split(' ', created_at) status.created_at = created_split[0] + ' ' + created_split[2] + ' ' + created_split[1] + ' ' + created_split[4] + ' ' + created_split[5] + ' ' + created_split[3] status.text = result.text + + # If this is in reply to something, get the relevant tweet + if result.to_user_id is not None: + try: + with api.lock: + tweet = api.GetStatus(result.id) + status.in_reply_to_status_id = tweet.in_reply_to_status_id + except (HTTPError, URLError): + pass # Just move along, leave off the 'in reply to' data + statuses.append(status) return statuses def dms_to_statuses(direct_messages): + """ + To make it easier for our widgets to handle, we convert Direct Message + results to our home-baked Status objects that mimic the REST API Statuses. + """ statuses = [] for dm in direct_messages: status = Status()