~ssh-rdp/deskbar-applet/history-count

« back to all changes in this revision

Viewing changes to deskbar/handlers/twitter.py

  • Committer: Sebastian Pölsterl
  • Date: 2008-08-06 20:44:17 UTC
  • mfrom: (1799.1.79)
  • Revision ID: marduk@k-d-w.org-20080806204417-pggs8ixku7roce1z
Merged latest trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from deskbar.core.GconfStore import GconfStore
 
2
from deskbar.core.Utils import strip_html, get_proxy, load_base64_icon
 
3
from deskbar.core.Web import GnomeURLopener, Account, AccountDialog, ConcurrentRequestsException
 
4
from deskbar.defs import VERSION
 
5
from deskbar.handlers.actions.CopyToClipboardAction import CopyToClipboardAction
 
6
from deskbar.handlers.actions.ShowUrlAction import ShowUrlAction
 
7
from gettext import gettext as _
 
8
from xml.sax.saxutils import unescape
 
9
import deskbar
 
10
import deskbar.interfaces.Action
 
11
import deskbar.interfaces.Match
 
12
import deskbar.interfaces.Module
 
13
import gtk
 
14
import gobject
 
15
import logging
 
16
import urllib
 
17
 
 
18
LOGGER = logging.getLogger (__name__)
 
19
 
 
20
TWITTER_UPDATE_URL = "http://twitter.com/statuses/update.xml"
 
21
IDENTICA_UPDATE_URL = "http://identi.ca/api/statuses/update.xml"
 
22
 
 
23
# Base64 encoded Twitter logo
 
24
TWITTER_ICON = \
 
25
"""iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAcVJREFUOI2FkztuFEEQhr/q7nnIa2GQVgiDCYCEAzhAHMY3gASJgAtwAXLuQ0AGRiQbOEBeGdsy4PXOTNdPMLOrWVbCJVXUVf+ru42h2pzVZEdmBEQwo07JuKUSgEta5szMjfNOTKLxvIDsrhjCf0ESABJXDl+WHTVw0sE0JB7gtwkYAIBG4mcWCVgCGTA5N22rngTMjBiMFKNtATjwx0Vh0Am+NpmzGPB+FwBDPEzQdFll6kESQAjBZjetfrsozDDEp0U3MmBrmAS8uldvW8jAlaBESGvVYIZJgDAz5tmZuzYB3F3fl5kLd+oRoQbZq/FO4mkZeFKETQADMuLSndqM6yxe3605rBJLaW0gI6YxUo6uNq0sNoK5i12DXy52gjExcSdFGCw5kP55FwH68wI4dXHiYubiW+skA7n3AxK44xoFMA7xcWGUZhxngcHbiwVnueIgBroVO/CyTuN91nKUO72/bHh3fg1xCGmDTCBjPxqfD/bYL/t3sI7TLfBmr+Jot4LO+9SCjTpANH50znGbNzMAiCFYNPh4f4cP0wnPklFJVBL10Lh4UScOq7htYVXZXblrWRA5deGjIQGPolEaVMNX/wuhBOJI5bQAKAAAAABJRU5ErkJggg=="""
 
26
 
 
27
IDENTICA_ICON = \
 
28
"""iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gIBRUoA+uuEZoAAACXSURBVDjLY5Q0cfzPQAFgYqAQDLwBLNgEOdjZGJRVpBmMDNQYGBgYGM5duMVw985Thh8/fxE2gIOdjcHVxZRBW1sRLiYtLcpw9ep9ht17TmMYguEFZRVpFM0woK2tyKCsIk04DGDOxgawyVE/Fs5duIVTMTY5DAPu3nnKcPXqfQyFV6/eZ7h75ymGOCO2pExKNDKO5gUGAHZcMhS+r1WkAAAAAElFTkSuQmCC"""
 
29
 
 
30
# Singleton ref to the loaded pixbufs
 
31
_twitter_pixbuf = load_base64_icon (TWITTER_ICON)
 
32
_identica_pixbuf = load_base64_icon (IDENTICA_ICON)
 
33
 
 
34
HANDLERS = ["TwitterModule", "IdenticaModule"]
 
35
VERSION = "0.3"
 
36
 
 
37
MIN_MESSAGE_LEN = 2
 
38
        
 
39
_FAIL_POST = _(
 
40
"""Failed to post update to %(domain)s. Please make sure that:
 
41
 
 
42
  - Your internet connection is working
 
43
  - You can connect to <i>http://%(domain)s</i> in your web browser
 
44
  - Your credentials in the preferences are correct
 
45
"""
 
46
)
 
47
        
 
48
class TwitterClient :
 
49
    def __init__ (self, domain="twitter.com", update_url=TWITTER_UPDATE_URL, realm="Twitter API"):
 
50
        self._account = Account (domain, realm)
 
51
        self._opener = GnomeURLopener (self._account)
 
52
        self._thread = None
 
53
        self._update_url = update_url
 
54
        self._domain = domain
 
55
        
 
56
        self._opener.connect ("done", self._on_opener_done)
 
57
        
 
58
    def update (self, msg):
 
59
        try:
 
60
            post_payload = urllib.urlencode({"status" : msg})
 
61
            self._opener.open_async (self._update_url, post_payload)
 
62
        except ConcurrentRequestsException :
 
63
            LOGGER.warning ("Attempting to post while another post is already running. Ignoring")
 
64
            error = gtk.MessageDialog (None,
 
65
                                       type=gtk.MESSAGE_WARNING,
 
66
                                       buttons=gtk.BUTTONS_OK)
 
67
            error.set_markup (_("A post is already awaiting submission, please wait before you post another message"))
 
68
            error.set_title (_("Error posting to %s" % self._domain))
 
69
            error.show_all()
 
70
            error.run()
 
71
            error.destroy()
 
72
            return
 
73
            
 
74
    def _on_opener_done (self, opener, info):
 
75
        LOGGER.debug ("Got reply from %s. Success: %s" % (self._update_url, self._opener.get_success()))
 
76
        if not self._opener.get_success() :
 
77
            error = gtk.MessageDialog (None,
 
78
                                       type=gtk.MESSAGE_WARNING,
 
79
                                       buttons=gtk.BUTTONS_OK)
 
80
            error.set_markup (_FAIL_POST % {"domain" : self._domain})
 
81
            error.set_title (_("Error posting to %s" % self._domain))
 
82
            error.show_all()
 
83
            error.run()
 
84
            error.destroy()
 
85
 
 
86
class TwitterUpdateAction(deskbar.interfaces.Action):
 
87
    
 
88
    def __init__(self, msg, client, domain="twitter.com", service="Twitter", pixbuf=None):
 
89
        deskbar.interfaces.Action.__init__ (self, msg)
 
90
        
 
91
        global _twitter_pixbuf
 
92
        
 
93
        self._msg = msg
 
94
        self._client = client
 
95
        self._domain = domain
 
96
        self._service = service
 
97
        
 
98
        if pixbuf : self._pixbuf = pixbuf
 
99
        else : self._pixbuf = _twitter_pixbuf
 
100
    
 
101
    def get_hash(self):
 
102
        return "%s:%s" % (self._service,self._msg)
 
103
        
 
104
    def get_icon(self):
 
105
        # We use only pixbufs
 
106
        return None
 
107
    
 
108
    def get_pixbuf(self) :
 
109
        return self._pixbuf
 
110
    
 
111
    def activate(self, text=None):
 
112
        LOGGER.info ("Posting: '%s'" % self._msg)
 
113
        try:
 
114
            self._client.update (self._msg)
 
115
        except IOError, e:
 
116
            LOGGER.warning ("Failed to post to %s: %s" % (self._domain,e))
 
117
            error = gtk.MessageDialog (None,
 
118
                                       type=gtk.MESSAGE_WARNING,
 
119
                                       buttons=gtk.BUTTONS_OK)
 
120
            error.set_markup (_FAIL_POST % {"domain" : self._domain})
 
121
            error.set_title (_("Error posting to %s" % self._domain))
 
122
            error.show_all()
 
123
            error.run()
 
124
            error.destroy()
 
125
        
 
126
    def get_verb(self):
 
127
        return _('<small>(%(remain)s)</small> Post <i>"%(msg)s"</i>')
 
128
 
 
129
    def get_tooltip(self, text=None):
 
130
        return _("Update your %s account with the message:\n\n\t<i>%s</i>") % (self._service_name, self._msg)
 
131
        
 
132
    def get_name(self, text=None):
 
133
        return {"name": self._msg, "msg" : self._msg, "remain" : str(140 - len(self._msg))}
 
134
    
 
135
    def skip_history(self):
 
136
        return True
 
137
 
 
138
class TwitterMatch(deskbar.interfaces.Match):
 
139
    
 
140
    def __init__(self, msg, client, domain="twitter.com", service="Twitter", pixbuf=None, **args):
 
141
        global _twitter_pixbuf
 
142
        
 
143
        self._service = service
 
144
        self._domain = domain
 
145
        
 
146
        if pixbuf : self._pixbuf = pixbuf
 
147
        else : self._pixbuf = _twitter_pixbuf
 
148
        
 
149
        deskbar.interfaces.Match.__init__ (self,
 
150
                                           category="web",                                           
 
151
                                           name=msg,
 
152
                                           pixbuf=self._pixbuf,
 
153
                                           **args)
 
154
                                           
 
155
        action = TwitterUpdateAction(self.get_name(), client,
 
156
                                     domain=self._domain,
 
157
                                     service=self._service,
 
158
                                     pixbuf=self._pixbuf)
 
159
        self.add_action(action)
 
160
    
 
161
    def get_hash(self):
 
162
        return "%s:%s" % (self._service,self.get_name())
 
163
 
 
164
class TwitterModule(deskbar.interfaces.Module):
 
165
    
 
166
    INFOS = {'icon': _twitter_pixbuf,
 
167
             'name': _("Twitter"),
 
168
             'description': _("Post updates to your Twitter account"),
 
169
             'version': VERSION}
 
170
    
 
171
    def __init__(self, domain="twitter.com", service="Twitter", pixbuf=None, update_url=TWITTER_UPDATE_URL, realm="Twitter API"):
 
172
        global _twitter_pixbuf
 
173
        
 
174
        deskbar.interfaces.Module.__init__(self)
 
175
 
 
176
        self._domain = domain
 
177
        self._service = service
 
178
        self._realm = realm
 
179
        
 
180
        if pixbuf : self._pixbuf = pixbuf
 
181
        else : self._pixbuf = _twitter_pixbuf
 
182
        
 
183
        self._client = TwitterClient(domain=self._domain, update_url=update_url, realm=self._realm)
 
184
    
 
185
    def query(self, qstring):
 
186
        if len (qstring) <= MIN_MESSAGE_LEN and \
 
187
           len (qstring) > 140: return None
 
188
        
 
189
        match = TwitterMatch(qstring, self._client,
 
190
                             domain=self._domain,
 
191
                             service=self._service,
 
192
                             pixbuf=self._pixbuf)
 
193
        
 
194
        self._emit_query_ready(qstring, [match])
 
195
    
 
196
    def has_config(self):        
 
197
        return True
 
198
    
 
199
    def show_config(self, parent):
 
200
        LOGGER.debug ("Showing config")
 
201
        account = Account (self._domain, self._realm)
 
202
        
 
203
        login_dialog = AccountDialog(account)
 
204
        login_dialog.show_all()
 
205
        login_dialog.run()            
 
206
        login_dialog.destroy()
 
207
    
 
208
    def get_domain (self):
 
209
        return self._domain
 
210
    
 
211
class IdenticaModule(TwitterModule):
 
212
    
 
213
    INFOS = {'icon': _identica_pixbuf,
 
214
             'name': _("identi.ca"),
 
215
             'description': _("Post updates to your identi.ca account"),
 
216
             'version': VERSION}
 
217
    
 
218
    def __init__(self):
 
219
        TwitterModule.__init__(self,
 
220
                               domain="identi.ca",
 
221
                               service="Identica",
 
222
                               pixbuf=_identica_pixbuf,
 
223
                               update_url=IDENTICA_UPDATE_URL,
 
224
                               realm="Laconica API")
 
225