This repository has been archived on 2019-12-04. You can view files and clone it, but cannot push or open issues or pull requests.
hrafn/mytwitter.py

275 lines
9.4 KiB
Python
Executable File

#!/usr/bin/python
#
# Custom twitter client... mostly for learning Python
import sys, ConfigParser, os, re
import twitter
import gtk, gtk.glade, gobject
from urllib2 import HTTPError
from twitterwidgets import TweetPane
class MyTwitter():
""" Display Tweets, post to twitter """
def __init__(self):
config = ConfigParser.ConfigParser()
config.read(os.path.expanduser("~/.mytwitter"))
self.username = config.get('global', 'username')
self.password = config.get('global', 'password')
self.num_entries = int(config.get('global', 'entries'))
self.refresh_time = int(config.get('global', 'refreshtime'))
if self.refresh_time < 10:
self.refresh_time = 10
self.reply_id = None
# Authenticate with twitter, set up the API object
self.api = twitter.Api(username=self.username, password=self.password)
# Load up all the GUI stuff
self.init_user_interface('./default.glade')
self.init_widgets()
def init_user_interface(self, path_to_skin):
self.widget_tree=gtk.glade.XML(path_to_skin, "window")
self.widget_tree.signal_autoconnect(self)
def init_widgets(self):
# Get widgets from glade
self.tweet_notebook = self.widget_tree.get_widget('tweet_notebook')
self.view_menu = self.widget_tree.get_widget('view_menu')
self.update_entry = self.widget_tree.get_widget('update_entry')
self.update_count = self.widget_tree.get_widget('update_count')
self.status_bar = self.widget_tree.get_widget('status_bar')
self.search_entry = self.widget_tree.get_widget('search_entry')
self.following_button = self.widget_tree.get_widget('following_button')
self.context_id = self.status_bar.get_context_id('message')
self.tweet_notebook.remove_page(0) # kill the page that glade makes us have
# When we change tabs, any unread tweets in it become read
self.tweet_notebook.connect('switch_page', self.on_tab_change)
# Add the Home tab to the notebook
self.add_to_notebook('Home')
# Put Home, @user, and lists in the View menu...
lists = self.api.GetUserLists()
list_names = []
for l in lists['lists']:
list_names.append(l.name)
list_names.sort()
list_names.insert(0, 'Home')
list_names.insert(1, '@' + self.username)
for l in list_names:
menu_item = gtk.MenuItem(l)
self.view_menu.append(menu_item)
menu_item.connect('activate', self.on_view_selected, l)
menu_item.show()
# Timer to update periodically
self.update_windows()
gobject.timeout_add(self.refresh_time * 1000, self.update_windows)
def update_windows(self):
for i in range(0, self.tweet_notebook.get_n_pages()):
using_results = False
pane = self.tweet_notebook.get_nth_page(i)
list_name = pane.get_list_name()
if pane.get_single_tweet() is not None:
continue
elif list_name is None or list_name == 'Home':
statuses = self.api.GetHomeTimeline(count=self.num_entries)
elif list_name == '@' + self.username:
statuses = self.api.GetMentions(count=self.num_entries)
elif re.match(r'user: ', list_name):
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', list_name), count=self.num_entries)
elif re.match(r'[#|@]', list_name):
statuses = self.api.Search(list_name, rpp=self.num_entries)
using_results = True
else:
statuses = self.api.GetListStatuses(list_name, per_page=self.num_entries)
pane.update_window(statuses, using_results=using_results)
# We have to return true, so the timeout_add event will keep happening
return True
def update_windows_callback(self, widget):
self.update_windows()
def update_status(self):
text = self.update_entry.get_text()
self.update_entry.set_text("")
self.api.PostUpdate(text, in_reply_to_status_id=self.reply_id)
self.reply_id = None
self.update_status_bar('Tweet Posted')
def update_status_callback(self, widget):
self.update_status()
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"
self.update_count.set_label(new_count)
# If reply_id is set, unset it if we have removed the @ symbol
if self.reply_id is not None and not re.match('@', self.update_entry.get_text()):
self.reply_id = None
def gtk_main_quit(self, widget):
gtk.main_quit()
def on_about(self, widget):
print "STUB: help->about not yet implemented"
def on_reply(self, widget, data):
self.update_entry.set_text('@' + data['screen_name'] + ' ')
self.reply_id = data['id']
self.update_entry.grab_focus()
def on_retweet(self, widget, data):
self.api.PostRetweet(data['id'])
def on_reply_to(self, widget, data):
self.add_to_notebook(data['name'], data['id'])
def on_view_selected(self, event, name):
# If it already exists, don't add it, just switch to it
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.set_current_page(i)
return
# Now, add a new tab with this list
self.add_to_notebook(name)
# And, to propagate it:
self.update_windows()
# Remove one of the views from the tweet notebook.
# Called when the close button is clicked on one of the views
def remove_view(self, event, name):
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
def add_to_notebook(self, name, single_tweet=None):
is_user = False
following = False
if re.match('user:', name):
is_user = True
following = self.check_following(name)
new_pane = TweetPane(name, num_entries=self.num_entries, single_tweet=single_tweet, is_user=is_user, following=following)
self.tweet_notebook.append_page_menu(new_pane, new_pane.get_tab_label(), gtk.Label(name))
new_pane.get_tab_label().connect('close-clicked', self.remove_view, name)
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)
# 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
self.tweet_notebook.set_current_page(-1) # switch to the new pane
def on_tab_change(self, event, page, page_num):
pane = self.tweet_notebook.get_nth_page(page_num)
pane.set_tweets_read()
self.update_follow_button(pane)
def on_search(self, event):
search_string = self.search_entry.get_text()
self.search_entry.set_text('')
if re.match(r'[#|@]', search_string):
self.add_to_notebook(search_string)
else:
# Assume this is a user name we want to lookup
self.add_to_notebook('user: ' + search_string)
self.update_windows()
def update_status_bar(self, text):
self.status_bar.pop(self.context_id)
self.status_bar.push(self.context_id, text)
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):
print 'debug check_following(' + name + ')'
screen_name = re.sub('user: ', '', name)
relationship = self.api.ShowFriendships(target_screen_name=screen_name)
return relationship.source.following
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()
### end class MyTwitter
# main
my_twitter = MyTwitter()
gtk.main()