cairo-dock-team team mailing list archive
-
cairo-dock-team team
-
Mailing list archive
-
Message #03641
[Merge] lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into lp:cairo-dock-plug-ins-extras
Eduardo Mucelli Rezende Oliveira has proposed merging lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into lp:cairo-dock-plug-ins-extras.
Requested reviews:
Cairo-Dock Team (cairo-dock-team)
For more details, see:
https://code.launchpad.net/~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter/+merge/97325
Direct messages are shown in a gtk-based menu, and it is possible to reply them. Fixing the post method, and the stream callback.
--
https://code.launchpad.net/~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter/+merge/97325
Your team Cairo-Dock Team is requested to review the proposed merge of lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into lp:cairo-dock-plug-ins-extras.
=== modified file 'Twitter/ChangeLog'
--- Twitter/ChangeLog 2012-03-10 20:27:57 +0000
+++ Twitter/ChangeLog 2012-03-14 00:09:17 +0000
@@ -1,3 +1,4 @@
+0.1.3: (March/14/2012): Direct messages are shown in a gtk-based menu, and it is possible to reply them. Fixing the post method, and the stream callback.
0.1.2: (March/8/2012): Adding the emblem maker to inform the number of new tweets from the stream.
0.1.1: (March/6/2012): Using callback instead of a thread to check for the new tweet from the stream, faster, better, and cleaner. Fixed new tweets count that was not being updated. Increased modularization.
0.1: (March/5/2012): Finally, after long work, compatible with Twitter Stream, and using it to show the tweets that just arrived. Changed the "received" icon for direct messages, and added the "new" for new tweets, both are from the icon pack Basic made by Pixel Maker, http://pixel-mixer.com
=== modified file 'Twitter/Twitter'
--- Twitter/Twitter 2012-03-10 20:27:57 +0000
+++ Twitter/Twitter 2012-03-14 00:09:17 +0000
@@ -24,14 +24,14 @@
# The plugin is going to inform that you are successfully connected.
# To see the received tweets right-click on the icon -> Twitter -> New tweets.
-# To see the received direct messages right-click on the icon -> Twitter -> Received direct messages
+# To see the received direct messages right-click on the icon -> Twitter -> Received direct messages. You can reply one of them just by left-clicking on it.
# To see some user's info right-click on the icon -> Twitter -> Info
import os, webbrowser, simplejson, threading, Queue, urllib2
from oauth import oauth
from http import post, get #, stream
from util import *
-import emblem
+import emblem, menu
from CDApplet import CDApplet, _
# TODO import ConfigParser later conver files to config syntax
@@ -54,7 +54,7 @@
http_url = self.authorize_url)
oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
return oauth_request.to_url()
-
+
def get_unauthorized_request_token(self):
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url = self.request_token_url)
oauth_request.sign_request(self.signature_method, self.consumer, None)
@@ -103,39 +103,51 @@
buffer = ''
while True:
- chunk = req.read(1) # read character per character from the connection ...
+ chunk = req.read(1) # read character per character from the connection ...
if not chunk:
break
buffer += chunk
- tweets = buffer.split("\n",1) # ... until find the end of a tweet marked with a '\n'
+ tweets = buffer.split("\n",1) # ... until find the end of a tweet marked with a '\n'
if len(tweets) > 1:
content = tweets[0]
if "text" in content:
content = simplejson.loads(content)
logp("Received from Twitter Stream: %s" % content)
- self.callback(content) # at the moment this method is called 'on_receive_new_tweet_callback'
+ self.callback(content) # at the moment this method is called 'on_receive_new_entry_into_stream_callback'
buffer = tweets[1]
class TwitterAPI(API):
def __init__(self, access_key, access_secret):
API.__init__(self, access_key, access_secret)
- self.update_url = 'http://twitter.com/statuses/update.json'
- self.home_timeline_url = 'http://twitter.com/statuses/home_timeline.json'
- self.direct_messages_url = 'https://api.twitter.com/1/direct_messages.json'
- self.verify_credentials_url = 'https://api.twitter.com/1/account/verify_credentials.json'
+ self.update_url = 'http://twitter.com/statuses/update.json'
+ self.home_timeline_url = 'http://twitter.com/statuses/home_timeline.json'
+ self.direct_messages_url = 'https://api.twitter.com/1/direct_messages.json'
+ self.new_direct_messages_url = 'https://api.twitter.com/1/direct_messages/new.json'
+ self.verify_credentials_url = 'https://api.twitter.com/1/account/verify_credentials.json'
def tweet(self, message): # popularly "send a tweet"
+ params = {'status':message}
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
token = self.access_token,
http_url = self.update_url,
- parameters = {'status':message},
+ parameters = params,
http_method = "POST")
oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
- post_data = oauth_request.to_postdata()
- return post(self.update_url, post_data)
+ header = oauth_request.to_header()
+ post(self.update_url, params, header)
+ def new_direct_message(self, message, destinatary):
+ params = {'text':message, 'screen_name':destinatary}
+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
+ token = self.access_token,
+ http_url = self.new_direct_messages_url,
+ parameters = params,
+ http_method = "POST")
+ oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
+ header = oauth_request.to_header()
+ post(self.new_direct_messages_url, params, header)
def home_timeline(self):
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
@@ -167,6 +179,11 @@
response = get(url)
return simplejson.loads(response)
+class Message:
+ def __init__(self, text, sender):
+ self.text = text
+ self.sender = sender
+
class User:
def __init__(self, screen_name="", access_key="", access_secret=""):
self.screen_name = screen_name
@@ -183,18 +200,22 @@
# Twitter methods
- # This method is a callback that is called as soon as a new tweet that arrives on the stream
+ # This method is a callback that is called as soon as a new entry arrives on the stream
# It is passed as parameter when creating the instance for the TwitterStreamAPI
- # TwitterStreamAPI(access_key, access_secret, self.on_receive_new_tweet_callback)
- # TODO: Make available an "Animation" option upon a new tweet arrival
- def on_receive_new_tweet_callback(self, tweet):
- if not tweet['user']['screen_name'] == self.user.screen_name:
- logp("Inserting new tweet on the stream Queue: %s" % tweet) # not sent by the own user
- self.stream.put(tweet) # put the new tweet on the stream queue
- self.emblem.update(self.stream.qsize()) # create the emblem with the counter
- self.icon.SetEmblem(self.emblem.emblem, CDApplet.EMBLEM_TOP_RIGHT + CDApplet.EMBLEM_PERSISTENT) # add emblem
- #self.icon.SetQuickInfo(str(self.stream.qsize())) # update the new tweets counter on the icon
+ # TwitterStreamAPI(access_key, access_secret, self.on_receive_new_entry_into_stream_callback)
+ # TODO: Make available an "Animation" option upon a new entry arrival
+ # TODO: Consider the direct messages arriving on the stream
+ # Create two Queues to deal with tweets and messages separately
+ def on_receive_new_entry_into_stream_callback(self, entry):
+ #if 'direct_message' in entry: #TODO direct message
+ if 'user' in entry: # tweet
+ if not entry['user']['screen_name'] == self.user.screen_name:
+ logp("Inserting new tweet on the stream Queue: %s" % entry) # not sent by the own user
+ self.stream.put(entry) # put the new tweet on the stream queue
+ self.emblem.update(self.stream.qsize()) # create the emblem with the counter
+ self.icon.SetEmblem(self.emblem.emblem, CDApplet.EMBLEM_TOP_RIGHT + CDApplet.EMBLEM_PERSISTENT) # add emblem
+ # TODO: Use the Menu class
def show_new_tweets(self):
self.inform_start_of_waiting_process()
message = ''
@@ -206,11 +227,12 @@
self.inform_end_of_waiting_process()
self.show_popup_message(message, dialog)
+ # TODO: Use the Menu class
def show_home_timeline(self):
self.inform_start_of_waiting_process()
timeline = self.api.home_timeline()
if len(timeline) > 0:
- message = "".join (["[<b>%s</b>] %s\n" % (status['user']['name'], status['text']) for status in timeline])
+ message = "".join (["[<b>%s</b>] %s\n" % (status['user']['screen_name'], status['text']) for status in timeline])
else:
message = _("Oh, dear, your timeline is empty :-(")
dialog = {'use-markup':True}
@@ -220,13 +242,30 @@
def show_direct_messages(self):
self.inform_start_of_waiting_process()
messages = self.api.direct_messages()
+ # message = ""
+ itens = []
if len(messages) > 0:
- message = "".join (["[<b>%s</b>] %s\n" % (status['sender']['name'], status['text']) for status in messages])
+ # Message (content of text, nick name of who sent it)
+ ([itens.append(Message(status['text'], status['sender']['screen_name'])) for status in messages])
+ #message += "[<b>%s</b>] %s\n" % (sender, text)
+ direct_messages_list_menu = menu.Menu(itens, self.on_direct_messages_list_menu_clicked)
+ direct_messages_list_menu.pop_up(self.icon)
+ #message = "".join (["[<b>%s</b>] %s\n" % (status['sender']['screen_name'], status['text']) for status in messages])
else:
message = _("Oh, dear, you do not have direct messages :-(")
dialog = {'use-markup':True}
self.inform_end_of_waiting_process()
- self.show_popup_message(message, dialog)
+ #self.show_popup_message(message, dialog)
+
+ def on_direct_messages_list_menu_clicked(self, widget):
+ self.ask_for_direct_message_reply(widget.get_label()) # label holds the sender of the message, reply to him/her now
+
+ def ask_for_direct_message_reply(self, destinatary):
+ dialog = {'buttons':'ok;cancel'}
+ widget = {'widget-type':'text-entry', 'nb-chars':140} # 140 characters max, a direct message
+ self.show_popup_message((_("%s, write a reply to %s")) % (self.user.screen_name, destinatary), dialog, widget)
+ self.dialog_type = self.responding_sending_direct_message_reply
+ self.replying_direct_message_to = destinatary
def tweet(self, message): # popularly "send a tweet"
self.inform_start_of_waiting_process()
@@ -349,7 +388,8 @@
self.api = None
self.stream_api = None
(self.responding_screen_name, self.responding_authorization, self.responding_pin,
- self.responding_success, self.responding_tweet, self.responding_initial_informations) = range(6)
+ self.responding_success, self.responding_tweet, self.responding_initial_informations,
+ self.responding_sending_direct_message_reply) = range(7)
self.dialog_type = None
self.emblem = emblem.Emblem() # emblem maker, see emblem.py
@@ -358,6 +398,7 @@
self.user_stream_menu_id = 3000
self.stream = Queue.Queue()
+ #self.direct_messages = {}
CDApplet.__init__(self) # call CDApplet interface init
@@ -371,7 +412,7 @@
logp("User '%s' found" % self.user.screen_name)
self.api = TwitterAPI(self.user.access_key, self.user.access_secret) # getting control over the api
# setting the callback to receive the data of every entry on the stream
- self.stream_api = TwitterStreamAPI(self.user.access_key, self.user.access_secret, self.on_receive_new_tweet_callback)
+ self.stream_api = TwitterStreamAPI(self.user.access_key, self.user.access_secret, self.on_receive_new_entry_into_stream_callback)
#def reload(self):
#self.read_user_data()
@@ -401,6 +442,9 @@
elif self.dialog_type == self.responding_tweet:
logp("Sending a tweet '%s'" % content)
self.api.tweet(content)
+ elif self.dialog_type == self.responding_sending_direct_message_reply:
+ logp("Sending a direct message '%s'" % content)
+ self.api.new_direct_message(content, self.replying_direct_message_to)
def on_click(self, key):
self.ask_for_tweet()
=== modified file 'Twitter/Twitter.conf'
--- Twitter/Twitter.conf 2012-03-10 17:13:47 +0000
+++ Twitter/Twitter.conf 2012-03-14 00:09:17 +0000
@@ -1,4 +1,4 @@
-#!en;0.1.2
+#!en;0.1.3
#[gtk-about]
[Icon]
=== modified file 'Twitter/auto-load.conf'
--- Twitter/auto-load.conf 2012-03-10 20:27:57 +0000
+++ Twitter/auto-load.conf 2012-03-14 00:09:17 +0000
@@ -4,13 +4,13 @@
author = Eduardo Mucelli Rezende Oliveira
# A short description of the applet and how to use it.
-description = You can send tweets, see your timeline, the received directed messages, and new tweets.\nOn the first time, the applet is going to ask your nickname and authorization to connect with Twitter.\nThe applet is going to open your browser with the authorization page\nAs soon as you authorize it, a PIN number will be shown on the page, copy this number\nPaste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.\nTo see the received direct messages right-click on the icon -> Twitter -> Received direct messages.\nTo see some user's info right-click on the icon -> Twitter -> Info.\nTo see the received tweets right-click on the icon -> Twitter -> New tweets.
+description = You can send tweets, see your timeline, the received directed messages, and new tweets.\nOn the first time, the applet is going to ask your nickname and authorization to connect with Twitter.\nThe applet is going to open your browser with the authorization page\nAs soon as you authorize it, a PIN number will be shown on the page, copy this number\nPaste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.\nTo see the received direct messages right-click on the icon -> Twitter -> Received direct messages. You can reply one of them just by left-clicking on it.\nTo see some user's info right-click on the icon -> Twitter -> Info.\nTo see the received tweets right-click on the icon -> Twitter -> New tweets.
# Category of the applet : 2 = files, 3 = internet, 4 = Desktop, 5 = accessory, 6 = system, 7 = fun
category = 3
# Version of the applet; change it everytime you change something in the config file. Don't forget to update the version both in this file and in the config file.
-version = 0.1.2
+version = 0.1.3
# Whether the applet can be instanciated several times or not.
multi-instance = true
=== added file 'Twitter/data/received_menu.png'
Binary files Twitter/data/received_menu.png 1970-01-01 00:00:00 +0000 and Twitter/data/received_menu.png 2012-03-14 00:09:17 +0000 differ
=== modified file 'Twitter/http.py'
--- Twitter/http.py 2012-03-05 14:44:13 +0000
+++ Twitter/http.py 2012-03-14 00:09:17 +0000
@@ -5,32 +5,36 @@
# Author: Eduardo Mucelli Rezende Oliveira
# E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx
-import urllib2, json
+import urllib2, urllib
from util import logp, logm
# HTTP GET
def get(url, tries = 0):
- while True:
- try:
- logp("Trying to connect to %s" % url)
- request = urllib2.Request(url)
- response = urllib2.urlopen(request)
- return response.read()
- except urllib2.HTTPError:
- tries += 1
- if tries > 3:
- raise
+ while True:
+ try:
+ logp("GET: Trying to connect to %s" % url)
+ request = urllib2.Request(url)
+ response = urllib2.urlopen(request)
+ return response.read()
+ except urllib2.HTTPError:
+ tries += 1
+ if tries > 3:
+ raise
# HTTP POST
-def post(url, post_data, tries = 0):
- while True:
- try:
- return urllib2.urlopen(url, post_data)
- except urllib2.HTTPError:
- tries += 1
- if tries > 3:
- raise
-
+def post(url, params, header, tries = 0):
+ while True:
+ try:
+ logp("POST: Trying to connect to %s" % url)
+ data = urllib.urlencode(params)
+ request = urllib2.Request(url, data, headers=header)
+ response = urllib2.urlopen(request)
+ return response.read()
+ except urllib2.HTTPError:
+ tries += 1
+ if tries > 3:
+ raise
+
#def stream(url):
# req = urllib2.urlopen(url)
# buffer = ''
=== added file 'Twitter/menu.py'
--- Twitter/menu.py 1970-01-01 00:00:00 +0000
+++ Twitter/menu.py 2012-03-14 00:09:17 +0000
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+
+# This is a part of the external Twitter applet for Cairo-Dock
+#
+# Author: Eduardo Mucelli Rezende Oliveira
+# E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx
+
+import gtk, os
+
+class Menu(gtk.Menu):
+
+ def __init__(self, messages, callback):
+ gtk.Menu.__init__(self)
+
+ for message in messages:
+ text = "<b>%s</b>\n%s" % (message.sender, message.text)
+ item = gtk.ImageMenuItem()
+ # the true label is set after with set_markup()
+ item.set_label(message.sender)
+ item.set_image(gtk.image_new_from_file(os.path.abspath("./data/received_menu.png")))
+ item.get_children()[0].set_markup(text)
+ item.connect('activate', callback)
+ self.append(item)
+ item.show()
+ # add a separator if mail is not last in list
+ if messages.index(message) != len(messages) - 1:
+ separator = gtk.SeparatorMenuItem()
+ self.append(separator)
+
+ self.show_all()
+
+ def pop_up(self, icon):
+ self.icon = icon
+ self.popup(parent_menu_shell=None, parent_menu_item=None, func=self.get_xy, data=(400, 400), button=1, activate_time=0)
+
+ def get_xy(self, m, data):
+ # fetch icon geometry
+ icondata = self.icon.GetAll()
+ iconContainer = icondata['container']
+ iconOrientation = icondata['orientation']
+ iconWidth = icondata['width']
+ iconHeight = icondata['height']
+ iconPosX = icondata['x']
+ iconPosY = icondata['y']
+
+ # get menu geometry
+ menuWidth, menuHeight = m.size_request()
+
+ # adapt to container and orientation
+ if iconContainer == 1: # Then it's a desklet, always oriented in a bottom-like way.
+ if iconPosY['y'] < (gtk.gdk.screen_height() / 2):
+ iconOrientation = 1
+ else:
+ iconOrientation = 0
+
+ if iconOrientation == 0:
+ # compute position of menu
+ x = iconPosX - (menuWidth / 2)
+ y = iconPosY - (iconHeight / 2) - menuHeight
+
+ else:
+ x = iconPosX - (menuWidth / 2)
+ y = iconPosY + (iconHeight / 2)
+
+ return (x, y, True)
Follow ups