2010-04-07 03:05:51 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Custom twitter client... mostly for learning Python
|
|
|
|
|
2010-04-17 02:44:22 +00:00
|
|
|
import sys, ConfigParser, os, re, optparse, shelve
|
2010-04-13 21:32:04 +00:00
|
|
|
import twitter
|
|
|
|
import gtk, gtk.glade, gobject
|
|
|
|
from urllib2 import HTTPError
|
2010-04-14 15:03:20 +00:00
|
|
|
from twitterwidgets import TweetPane
|
2010-04-07 03:05:51 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
class MyTwitter():
|
2010-04-07 03:05:51 +00:00
|
|
|
|
|
|
|
""" Display Tweets, post to twitter """
|
|
|
|
|
2010-04-14 21:58:52 +00:00
|
|
|
def __init__(self, config_file):
|
2010-04-07 17:17:21 +00:00
|
|
|
config = ConfigParser.ConfigParser()
|
2010-04-14 21:58:52 +00:00
|
|
|
config.read(os.path.expanduser(config_file))
|
2010-04-07 17:17:21 +00:00
|
|
|
self.username = config.get('global', 'username')
|
|
|
|
self.password = config.get('global', 'password')
|
2010-04-07 18:47:16 +00:00
|
|
|
self.num_entries = int(config.get('global', 'entries'))
|
|
|
|
self.refresh_time = int(config.get('global', 'refreshtime'))
|
2010-04-17 02:44:22 +00:00
|
|
|
|
|
|
|
db_file = os.path.expanduser(config.get('global', 'dbfile'))
|
|
|
|
self.db = shelve.open(db_file)
|
|
|
|
|
2010-04-19 14:53:28 +00:00
|
|
|
if not self.db.has_key('open_tabs'):
|
|
|
|
self.db['open_tabs'] = ['Home', '@' + self.username, 'Direct Messages']
|
|
|
|
|
2010-04-08 21:07:27 +00:00
|
|
|
if self.refresh_time < 10:
|
|
|
|
self.refresh_time = 10
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
self.reply_id = None
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Authenticate with twitter, set up the API object
|
|
|
|
self.api = twitter.Api(username=self.username, password=self.password)
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Load up all the GUI stuff
|
|
|
|
self.init_user_interface('./default.glade')
|
|
|
|
self.init_widgets()
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def init_user_interface(self, path_to_skin):
|
|
|
|
self.widget_tree=gtk.glade.XML(path_to_skin, "window")
|
|
|
|
self.widget_tree.signal_autoconnect(self)
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def init_widgets(self):
|
2010-04-12 18:11:27 +00:00
|
|
|
# Get widgets from glade
|
|
|
|
self.tweet_notebook = self.widget_tree.get_widget('tweet_notebook')
|
|
|
|
self.view_menu = self.widget_tree.get_widget('view_menu')
|
2010-04-08 20:39:56 +00:00
|
|
|
self.update_entry = self.widget_tree.get_widget('update_entry')
|
|
|
|
self.update_count = self.widget_tree.get_widget('update_count')
|
2010-04-11 05:37:09 +00:00
|
|
|
self.status_bar = self.widget_tree.get_widget('status_bar')
|
2010-04-12 21:58:00 +00:00
|
|
|
self.search_entry = self.widget_tree.get_widget('search_entry')
|
2010-04-14 18:24:40 +00:00
|
|
|
self.following_button = self.widget_tree.get_widget('following_button')
|
2010-04-16 03:00:35 +00:00
|
|
|
self.at_button = self.widget_tree.get_widget('at_button')
|
2010-04-16 21:32:17 +00:00
|
|
|
self.verified_label = self.widget_tree.get_widget('verified_label')
|
2010-04-12 21:58:00 +00:00
|
|
|
|
2010-04-11 05:44:44 +00:00
|
|
|
self.context_id = self.status_bar.get_context_id('message')
|
2010-04-07 17:21:55 +00:00
|
|
|
|
2010-04-12 18:11:27 +00:00
|
|
|
self.tweet_notebook.remove_page(0) # kill the page that glade makes us have
|
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
# When we change tabs, any unread tweets in it become read
|
|
|
|
self.tweet_notebook.connect('switch_page', self.on_tab_change)
|
|
|
|
|
2010-04-19 14:53:28 +00:00
|
|
|
# Add the tabs from last session to the notebook
|
|
|
|
for tab in self.db['open_tabs']:
|
|
|
|
self.add_to_notebook(tab)
|
2010-04-08 20:39:56 +00:00
|
|
|
|
2010-04-16 19:10:33 +00:00
|
|
|
# Put Home, @user, Direct Messages, and lists in the View menu...
|
2010-04-08 21:07:27 +00:00
|
|
|
lists = self.api.GetUserLists()
|
2010-04-11 04:45:41 +00:00
|
|
|
list_names = []
|
2010-04-08 21:07:27 +00:00
|
|
|
for l in lists['lists']:
|
2010-04-11 04:45:41 +00:00
|
|
|
list_names.append(l.name)
|
|
|
|
list_names.sort()
|
2010-04-12 18:50:04 +00:00
|
|
|
list_names.insert(0, 'Home')
|
|
|
|
list_names.insert(1, '@' + self.username)
|
2010-04-16 19:10:33 +00:00
|
|
|
list_names.insert(2, 'Direct Messages')
|
2010-04-11 04:45:41 +00:00
|
|
|
for l in list_names:
|
2010-04-12 18:50:04 +00:00
|
|
|
menu_item = gtk.MenuItem(l)
|
|
|
|
self.view_menu.append(menu_item)
|
|
|
|
menu_item.connect('activate', self.on_view_selected, l)
|
|
|
|
menu_item.show()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
# Timer to update periodically
|
2010-04-12 18:50:04 +00:00
|
|
|
gobject.timeout_add(self.refresh_time * 1000, self.update_windows)
|
2010-04-08 19:12:57 +00:00
|
|
|
|
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def update_windows(self):
|
2010-04-12 19:19:09 +00:00
|
|
|
for i in range(0, self.tweet_notebook.get_n_pages()):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
2010-04-12 18:50:04 +00:00
|
|
|
list_name = pane.get_list_name()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
2010-04-14 14:58:16 +00:00
|
|
|
if pane.get_single_tweet() is not None:
|
2010-04-13 20:55:26 +00:00
|
|
|
continue
|
|
|
|
elif list_name is None or list_name == 'Home':
|
2010-04-12 18:50:04 +00:00
|
|
|
statuses = self.api.GetHomeTimeline(count=self.num_entries)
|
|
|
|
elif list_name == '@' + self.username:
|
|
|
|
statuses = self.api.GetMentions(count=self.num_entries)
|
2010-04-16 19:10:33 +00:00
|
|
|
elif list_name == 'Direct Messages':
|
|
|
|
statuses = self.dms_to_statuses(self.api.GetDirectMessages())
|
2010-04-12 21:58:00 +00:00
|
|
|
elif re.match(r'user: ', list_name):
|
|
|
|
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', list_name), count=self.num_entries)
|
2010-04-16 02:37:13 +00:00
|
|
|
elif re.match(r'list: ', list_name):
|
|
|
|
statuses = self.api.GetListStatuses(re.sub(r'^list: ', r'', list_name), per_page=self.num_entries)
|
|
|
|
else:
|
2010-04-16 19:10:33 +00:00
|
|
|
statuses = self.results_to_statuses(self.api.Search(list_name, rpp=self.num_entries))
|
2010-04-12 20:53:03 +00:00
|
|
|
|
2010-04-16 19:10:33 +00:00
|
|
|
pane.update_window(statuses)
|
2010-04-11 05:37:09 +00:00
|
|
|
|
2010-04-12 21:21:14 +00:00
|
|
|
# We have to return true, so the timeout_add event will keep happening
|
|
|
|
return True
|
|
|
|
|
2010-04-07 18:17:57 +00:00
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def update_windows_callback(self, widget):
|
|
|
|
self.update_windows()
|
2010-04-08 21:07:27 +00:00
|
|
|
|
|
|
|
|
2010-04-07 18:17:57 +00:00
|
|
|
def update_status(self):
|
2010-04-08 20:39:56 +00:00
|
|
|
text = self.update_entry.get_text()
|
2010-04-08 21:07:27 +00:00
|
|
|
self.update_entry.set_text("")
|
2010-04-09 05:08:32 +00:00
|
|
|
self.api.PostUpdate(text, in_reply_to_status_id=self.reply_id)
|
|
|
|
self.reply_id = None
|
2010-04-14 14:58:16 +00:00
|
|
|
self.update_status_bar('Tweet Posted')
|
2010-04-07 18:17:57 +00:00
|
|
|
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
def update_status_callback(self, widget):
|
2010-04-07 18:17:57 +00:00
|
|
|
self.update_status()
|
2010-04-07 18:07:26 +00:00
|
|
|
|
2010-04-07 03:05:51 +00:00
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
def text_watcher(self, widget):
|
|
|
|
''' Watch text entered on the update_entry, update things '''
|
|
|
|
text_len = self.update_entry.get_text_length()
|
|
|
|
new_count = str(text_len) + "/140"
|
2010-04-08 20:39:56 +00:00
|
|
|
self.update_count.set_label(new_count)
|
|
|
|
|
2010-04-09 21:45:21 +00:00
|
|
|
# If reply_id is set, unset it if we have removed the @ symbol
|
2010-04-14 14:58:16 +00:00
|
|
|
if self.reply_id is not None and not re.match('@', self.update_entry.get_text()):
|
2010-04-09 21:45:21 +00:00
|
|
|
self.reply_id = None
|
|
|
|
|
2010-04-08 20:39:56 +00:00
|
|
|
|
|
|
|
def gtk_main_quit(self, widget):
|
2010-04-17 02:44:22 +00:00
|
|
|
self.db.close()
|
2010-04-08 20:39:56 +00:00
|
|
|
gtk.main_quit()
|
|
|
|
|
|
|
|
|
|
|
|
def on_about(self, widget):
|
2010-04-09 21:45:21 +00:00
|
|
|
print "STUB: help->about not yet implemented"
|
2010-04-08 19:12:57 +00:00
|
|
|
|
2010-04-07 19:54:54 +00:00
|
|
|
|
2010-04-14 14:58:16 +00:00
|
|
|
def on_reply(self, widget, data):
|
|
|
|
self.update_entry.set_text('@' + data['screen_name'] + ' ')
|
|
|
|
self.reply_id = data['id']
|
2010-04-09 21:45:21 +00:00
|
|
|
self.update_entry.grab_focus()
|
2010-04-09 04:56:51 +00:00
|
|
|
|
|
|
|
|
2010-04-14 14:58:16 +00:00
|
|
|
def on_retweet(self, widget, data):
|
|
|
|
self.api.PostRetweet(data['id'])
|
2010-04-09 04:56:51 +00:00
|
|
|
|
2010-04-12 01:14:24 +00:00
|
|
|
|
2010-04-13 21:32:04 +00:00
|
|
|
def on_reply_to(self, widget, data):
|
|
|
|
self.add_to_notebook(data['name'], data['id'])
|
|
|
|
|
|
|
|
|
2010-04-12 18:50:04 +00:00
|
|
|
def on_view_selected(self, event, name):
|
2010-04-16 19:10:33 +00:00
|
|
|
if name == 'Home' or name == '@' + self.username or name == 'Direct Messages':
|
2010-04-16 02:43:48 +00:00
|
|
|
full_name = name
|
|
|
|
else:
|
|
|
|
full_name = 'list: ' + name
|
2010-04-16 02:37:13 +00:00
|
|
|
|
2010-04-12 19:19:09 +00:00
|
|
|
# Now, add a new tab with this list
|
2010-04-16 02:37:13 +00:00
|
|
|
self.add_to_notebook(full_name)
|
2010-04-12 18:50:04 +00:00
|
|
|
|
2010-04-12 19:34:45 +00:00
|
|
|
|
|
|
|
# Remove one of the views from the tweet notebook.
|
|
|
|
# Called when the close button is clicked on one of the views
|
2010-04-19 14:53:28 +00:00
|
|
|
# or Ctrl + W is pressed while the view is active
|
2010-04-16 18:39:37 +00:00
|
|
|
def remove_view(self, name):
|
2010-04-19 14:53:28 +00:00
|
|
|
ot = self.db['open_tabs']
|
|
|
|
ot.remove(name)
|
|
|
|
self.db['open_tabs'] = ot
|
|
|
|
|
2010-04-12 19:34:45 +00:00
|
|
|
for i in range(self.tweet_notebook.get_n_pages()):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
|
|
|
if (pane.get_list_name() == name):
|
|
|
|
self.tweet_notebook.remove_page(i)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2010-04-16 18:39:37 +00:00
|
|
|
def remove_view_callback(self, event, name):
|
|
|
|
self.remove_view(name)
|
|
|
|
|
|
|
|
|
2010-04-13 20:56:33 +00:00
|
|
|
def add_to_notebook(self, name, single_tweet=None):
|
2010-04-16 03:02:14 +00:00
|
|
|
# If it already exists, don't add it, just switch to it
|
2010-04-16 02:43:48 +00:00
|
|
|
for i in range(self.tweet_notebook.get_n_pages()):
|
2010-04-16 03:02:14 +00:00
|
|
|
pane = self.tweet_notebook.get_nth_page(i)
|
2010-04-16 15:29:56 +00:00
|
|
|
# Unless it is a single tweet... ignore those unless
|
|
|
|
# we are also a single tweet... then, special logic
|
|
|
|
if pane.get_single_tweet() is not None:
|
|
|
|
if pane.get_single_tweet() == single_tweet:
|
|
|
|
self.tweet_notebook.set_current_page(i)
|
|
|
|
return
|
|
|
|
|
|
|
|
elif pane.get_list_name() == name:
|
2010-04-16 03:02:14 +00:00
|
|
|
self.tweet_notebook.set_current_page(i)
|
2010-04-16 02:43:48 +00:00
|
|
|
return
|
|
|
|
|
2010-04-19 14:53:28 +00:00
|
|
|
# We check for the name so that the special case of
|
|
|
|
# the first run is handled...
|
|
|
|
if single_tweet is None and name not in self.db['open_tabs']:
|
|
|
|
ot = self.db['open_tabs']
|
|
|
|
ot.append(name)
|
|
|
|
self.db['open_tabs'] = ot
|
|
|
|
|
2010-04-14 16:54:03 +00:00
|
|
|
is_user = False
|
|
|
|
following = False
|
2010-04-16 21:32:17 +00:00
|
|
|
verified = False
|
2010-04-14 16:54:03 +00:00
|
|
|
if re.match('user:', name):
|
|
|
|
is_user = True
|
2010-04-14 18:24:40 +00:00
|
|
|
following = self.check_following(name)
|
2010-04-16 21:32:17 +00:00
|
|
|
verified = self.check_verified(name)
|
|
|
|
new_pane = TweetPane(name, num_entries=self.num_entries, single_tweet=single_tweet, is_user=is_user, following=following, verified=verified)
|
2010-04-14 18:24:40 +00:00
|
|
|
self.tweet_notebook.append_page_menu(new_pane, new_pane.get_tab_label(), gtk.Label(name))
|
2010-04-16 18:39:37 +00:00
|
|
|
new_pane.get_tab_label().connect('close-clicked', self.remove_view_callback, name)
|
2010-04-14 14:58:16 +00:00
|
|
|
new_pane.connect('tweet-reply', self.on_reply)
|
|
|
|
new_pane.connect('tweet-retweet', self.on_retweet)
|
|
|
|
new_pane.connect('tweet-in-reply-to', self.on_reply_to)
|
2010-04-16 02:37:13 +00:00
|
|
|
new_pane.connect('show-user', self.show_user_callback)
|
2010-04-14 14:58:16 +00:00
|
|
|
|
|
|
|
# Special logic for single tweet pane
|
|
|
|
if single_tweet is not None:
|
|
|
|
try:
|
|
|
|
statuses = []
|
|
|
|
statuses.append(self.api.GetStatus(single_tweet))
|
|
|
|
new_pane.update_window(statuses)
|
|
|
|
except HTTPError:
|
|
|
|
self.tweet_notebook.remove_page(-1)
|
|
|
|
self.update_status_bar('Error retrieving tweet id: ' + str(single_tweet))
|
|
|
|
return
|
|
|
|
|
2010-04-16 03:00:35 +00:00
|
|
|
self.update_windows()
|
2010-04-12 20:53:03 +00:00
|
|
|
self.tweet_notebook.set_current_page(-1) # switch to the new pane
|
2010-04-12 19:34:45 +00:00
|
|
|
|
|
|
|
|
2010-04-12 21:12:11 +00:00
|
|
|
def on_tab_change(self, event, page, page_num):
|
|
|
|
pane = self.tweet_notebook.get_nth_page(page_num)
|
|
|
|
pane.set_tweets_read()
|
2010-04-14 18:24:40 +00:00
|
|
|
self.update_follow_button(pane)
|
2010-04-16 03:00:35 +00:00
|
|
|
if pane.get_is_user():
|
|
|
|
self.at_button.show()
|
|
|
|
else:
|
|
|
|
self.at_button.hide()
|
2010-04-16 21:32:17 +00:00
|
|
|
if pane.get_verified():
|
|
|
|
self.verified_label.show()
|
|
|
|
else:
|
|
|
|
self.verified_label.hide()
|
2010-04-12 21:12:11 +00:00
|
|
|
|
2010-04-12 21:58:00 +00:00
|
|
|
|
|
|
|
def on_search(self, event):
|
|
|
|
search_string = self.search_entry.get_text()
|
|
|
|
self.search_entry.set_text('')
|
2010-04-16 02:37:13 +00:00
|
|
|
self.add_to_notebook(search_string)
|
2010-04-12 21:58:00 +00:00
|
|
|
|
|
|
|
|
2010-04-14 14:58:16 +00:00
|
|
|
def update_status_bar(self, text):
|
|
|
|
self.status_bar.pop(self.context_id)
|
|
|
|
self.status_bar.push(self.context_id, text)
|
|
|
|
|
2010-04-14 18:24:40 +00:00
|
|
|
|
|
|
|
def on_following_button_clicked(self, event):
|
|
|
|
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
|
|
|
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
|
|
|
if current_pane.get_following():
|
|
|
|
self.api.DestroyFriendship(user_name)
|
|
|
|
current_pane.set_following(self.check_following(user_name))
|
|
|
|
else:
|
|
|
|
self.api.CreateFriendship(user_name)
|
|
|
|
current_pane.set_following(self.check_following(user_name))
|
|
|
|
|
|
|
|
self.update_follow_button(current_pane)
|
|
|
|
|
|
|
|
|
|
|
|
# Name is the name of a pane, with the 'user: ' in place
|
|
|
|
def check_following(self, name):
|
|
|
|
screen_name = re.sub('user: ', '', name)
|
|
|
|
relationship = self.api.ShowFriendships(target_screen_name=screen_name)
|
|
|
|
return relationship.source.following
|
|
|
|
|
|
|
|
|
2010-04-16 21:32:17 +00:00
|
|
|
# Name is the name of a pane, with the 'user: ' in place
|
|
|
|
def check_verified(self, name):
|
|
|
|
screen_name = re.sub('user: ', '', name)
|
|
|
|
user = self.api.GetUser(screen_name)
|
|
|
|
return user.verified
|
|
|
|
|
|
|
|
|
2010-04-14 18:24:40 +00:00
|
|
|
def update_follow_button(self, pane):
|
|
|
|
if not pane.get_is_user():
|
|
|
|
self.following_button.set_label('')
|
|
|
|
self.following_button.hide()
|
|
|
|
elif pane.get_following():
|
|
|
|
self.following_button.set_label('Unfollow')
|
|
|
|
self.following_button.show()
|
|
|
|
else:
|
|
|
|
self.following_button.set_label('Follow')
|
|
|
|
self.following_button.show()
|
|
|
|
|
|
|
|
|
2010-04-16 02:37:13 +00:00
|
|
|
def show_user(self, name):
|
|
|
|
self.add_to_notebook('user: ' + name)
|
|
|
|
|
|
|
|
|
|
|
|
def show_user_callback(self, widget, data):
|
|
|
|
self.show_user(data)
|
|
|
|
|
|
|
|
|
2010-04-16 03:00:35 +00:00
|
|
|
def on_at_button_clicked(self, widget):
|
|
|
|
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
|
|
|
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
|
|
|
self.add_to_notebook('@' + user_name)
|
|
|
|
|
|
|
|
|
2010-04-16 18:39:37 +00:00
|
|
|
def global_key_press_handler(self, widget, event):
|
|
|
|
keyname = gtk.gdk.keyval_name(event.keyval)
|
|
|
|
if keyname == 'w' and event.state & gtk.gdk.CONTROL_MASK:
|
|
|
|
self.close_current_tab()
|
|
|
|
|
|
|
|
|
|
|
|
def close_current_tab(self):
|
|
|
|
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
|
|
|
self.remove_view(current_pane.get_list_name())
|
|
|
|
|
|
|
|
|
2010-04-16 19:10:33 +00:00
|
|
|
# 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(self, results):
|
|
|
|
statuses = []
|
|
|
|
for result in results.results:
|
|
|
|
status = Status()
|
|
|
|
status.id = result.id
|
|
|
|
status.user = User()
|
|
|
|
status.user.screen_name = result.from_user
|
|
|
|
status.user.name = ""
|
|
|
|
status.in_reply_to_screen_name = result.to_user
|
|
|
|
# The Twitter Search API has different timestamps than the
|
|
|
|
# REST API... balls
|
|
|
|
# fixme:
|
|
|
|
# Gotta be a cleaner way to do this, but I can't think of it
|
|
|
|
# right now
|
|
|
|
created_at = re.sub(',', '', result.created_at)
|
|
|
|
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
|
|
|
|
statuses.append(status)
|
|
|
|
return statuses
|
|
|
|
|
|
|
|
|
|
|
|
def dms_to_statuses(self, direct_messages):
|
|
|
|
statuses = []
|
|
|
|
for dm in direct_messages:
|
|
|
|
status = Status()
|
|
|
|
status.id = dm.id
|
|
|
|
status.user = User()
|
|
|
|
status.user.screen_name = dm.sender.screen_name
|
|
|
|
status.user.name = dm.sender.name
|
|
|
|
status.created_at = dm.created_at
|
|
|
|
status.text = dm.text
|
|
|
|
statuses.append(status)
|
|
|
|
return statuses
|
|
|
|
|
2010-04-09 04:56:51 +00:00
|
|
|
### end class MyTwitter
|
|
|
|
|
|
|
|
|
2010-04-16 19:10:33 +00:00
|
|
|
# We use these classes to emulate a Status object when we need
|
|
|
|
# one to be built out of something else.
|
|
|
|
class Status():
|
|
|
|
def __init__(self):
|
|
|
|
self.user = User()
|
|
|
|
self.id = None
|
|
|
|
self.created_at = None
|
|
|
|
self.in_reply_to_screen_name = None
|
|
|
|
self.in_reply_to_status_id = None
|
|
|
|
|
|
|
|
class User():
|
|
|
|
def __init__(self):
|
|
|
|
self.screen_name = None
|
|
|
|
self.name = None
|
|
|
|
|
2010-04-13 02:10:51 +00:00
|
|
|
|
2010-04-07 03:05:51 +00:00
|
|
|
# main
|
2010-04-15 04:05:49 +00:00
|
|
|
parser = optparse.OptionParser()
|
|
|
|
parser.add_option('-c' ,'--config', dest="filename", default="~/.mytwitter")
|
|
|
|
(options, args) = parser.parse_args()
|
2010-04-09 21:45:21 +00:00
|
|
|
|
2010-04-15 04:05:49 +00:00
|
|
|
my_twitter = MyTwitter(options.filename)
|
2010-04-08 20:39:56 +00:00
|
|
|
gtk.main()
|