Merge lp:~sazius/heybuddy/minor_fixes into lp:heybuddy
- minor_fixes
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 347 |
Proposed branch: | lp:~sazius/heybuddy/minor_fixes |
Merge into: | lp:heybuddy |
Diff against target: |
226 lines (+84/-1) 5 files modified
Communicator.py (+7/-0) Dent.py (+4/-0) SettingsPage.py (+11/-0) XMLProcessor.py (+23/-0) heybuddy.py (+39/-1) |
To merge this branch: | bzr merge lp:~sazius/heybuddy/minor_fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mats Sjöberg (community) | Needs Resubmitting | ||
jezra | Pending | ||
Review via email: mp+180620@code.launchpad.net |
Commit message
Description of the change
When your StatusNet instance has a shorter character limit than someone posting remotely the posts will get truncated. This is very annoying. These posts, however contain an "attachment" in the XML which is an URL to the full text. This patch makes heybuddy fetch that for truncated posts.
(A minor fix is also that an URL in parentheses, e.g. "(http://
- 349. By Mats Sjöberg
-
Added a check if attachment size is a digit to avoid annoying error messages.
jezra (jezra) wrote : | # |
Mats Sjöberg (sazius) wrote : | # |
> Uh oh, this sounds like a "feature". Because this requires adding a new module
> and making an extra http request, there needs to be a preference option to
> enable this (it should be disabled by default).
You might argue if it is _really_ a new "feature" or not... :-) But yeah, maybe it's best to have it a preference option since it does add HTTP traffic. I'll add that and make a new merge request when done.
- 350. By Mats Sjöberg
-
Removed debugging output.
- 351. By Mats Sjöberg <email address hidden>
-
Dent expansion now with 100% more configurability!
Mats Sjöberg (sazius) wrote : | # |
OK, I now added a config check box, disabled by default. Also please note, that I'm not a Python and even less PyGTK expert so the code is far from perfect.
jezra (jezra) wrote : | # |
Did you have a tasty beverage while coding?
Mats Sjöberg (sazius) wrote : | # |
Yes, somewhat unusually I was drinking wine. Now I'm having a local ESB :-)
Preview Diff
1 | === modified file 'Communicator.py' | |||
2 | --- Communicator.py 2012-09-08 16:34:36 +0000 | |||
3 | +++ Communicator.py 2013-08-31 16:29:00 +0000 | |||
4 | @@ -113,6 +113,10 @@ | |||
5 | 113 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | 113 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, |
6 | 114 | (gobject.TYPE_STRING,gobject.TYPE_STRING,) | 114 | (gobject.TYPE_STRING,gobject.TYPE_STRING,) |
7 | 115 | ), | 115 | ), |
8 | 116 | 'attachment-received': ( | ||
9 | 117 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | ||
10 | 118 | (gobject.TYPE_STRING,gobject.TYPE_STRING,) | ||
11 | 119 | ), | ||
12 | 116 | } | 120 | } |
13 | 117 | 121 | ||
14 | 118 | def __init__(self, app_name=None, cert_file=None, apiroot="http://identi.ca/api", version=""): | 122 | def __init__(self, app_name=None, cert_file=None, apiroot="http://identi.ca/api", version=""): |
15 | @@ -422,3 +426,6 @@ | |||
16 | 422 | data = {'url':longurl, 'format':'simple'} | 426 | data = {'url':longurl, 'format':'simple'} |
17 | 423 | url = "http://is.gd/create.php?" + urlencode(data) | 427 | url = "http://is.gd/create.php?" + urlencode(data) |
18 | 424 | self.process_httprequest(url, 'shortened_url', longurl, True) | 428 | self.process_httprequest(url, 'shortened_url', longurl, True) |
19 | 429 | |||
20 | 430 | def fetch_attachment(self, url): | ||
21 | 431 | self.process_httprequest(url, 'attachment-received', url, True) | ||
22 | 425 | 432 | ||
23 | === modified file 'Dent.py' | |||
24 | --- Dent.py 2012-07-16 22:36:42 +0000 | |||
25 | +++ Dent.py 2013-08-31 16:29:00 +0000 | |||
26 | @@ -84,6 +84,7 @@ | |||
27 | 84 | vbox = gtk.VBox(False,0) | 84 | vbox = gtk.VBox(False,0) |
28 | 85 | #vbox.set_border_width(5) | 85 | #vbox.set_border_width(5) |
29 | 86 | user_box.pack_start(vbox,True,True,0) | 86 | user_box.pack_start(vbox,True,True,0) |
30 | 87 | |||
31 | 87 | self.text_label = gtk.Label() | 88 | self.text_label = gtk.Label() |
32 | 88 | self.text_label.set_markup( data['markup'] ) | 89 | self.text_label.set_markup( data['markup'] ) |
33 | 89 | self.text_label.set_alignment(0,0) | 90 | self.text_label.set_alignment(0,0) |
34 | @@ -214,6 +215,9 @@ | |||
35 | 214 | 215 | ||
36 | 215 | vbox.pack_start(hbox1,False,False,0) | 216 | vbox.pack_start(hbox1,False,False,0) |
37 | 216 | self.add(user_box) | 217 | self.add(user_box) |
38 | 218 | |||
39 | 219 | def update_text(self, text): | ||
40 | 220 | self.text_label.set_markup(text) | ||
41 | 217 | 221 | ||
42 | 218 | def event_box_realized(self,widget): | 222 | def event_box_realized(self,widget): |
43 | 219 | hand2 = gtk.gdk.Cursor(gtk.gdk.HAND2) | 223 | hand2 = gtk.gdk.Cursor(gtk.gdk.HAND2) |
44 | 220 | 224 | ||
45 | === modified file 'SettingsPage.py' | |||
46 | --- SettingsPage.py 2012-07-16 22:36:42 +0000 | |||
47 | +++ SettingsPage.py 2013-08-31 16:29:00 +0000 | |||
48 | @@ -21,6 +21,10 @@ | |||
49 | 21 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | 21 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, |
50 | 22 | (gobject.TYPE_BOOLEAN,) | 22 | (gobject.TYPE_BOOLEAN,) |
51 | 23 | ), | 23 | ), |
52 | 24 | 'option-expand-long-dents': ( | ||
53 | 25 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | ||
54 | 26 | (gobject.TYPE_BOOLEAN,) | ||
55 | 27 | ), | ||
56 | 24 | 'option-ctrl-enter': ( | 28 | 'option-ctrl-enter': ( |
57 | 25 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | 29 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, |
58 | 26 | (gobject.TYPE_BOOLEAN,) | 30 | (gobject.TYPE_BOOLEAN,) |
59 | @@ -148,6 +152,9 @@ | |||
60 | 148 | 152 | ||
61 | 149 | self.api_retweet = gtk.CheckButton(_("Use retweet API instead of default redent style")) | 153 | self.api_retweet = gtk.CheckButton(_("Use retweet API instead of default redent style")) |
62 | 150 | self.api_retweet.connect("toggled", self.option_toggled,'option-api-retweet') | 154 | self.api_retweet.connect("toggled", self.option_toggled,'option-api-retweet') |
63 | 155 | |||
64 | 156 | self.expand_long_dents = gtk.CheckButton(_("Expand too long dents from remote servers")) | ||
65 | 157 | self.expand_long_dents.connect("toggled", self.option_toggled, 'option-expand-long-dents') | ||
66 | 151 | 158 | ||
67 | 152 | self.enable_notifications = gtk.CheckButton(_("Enable notifications")) | 159 | self.enable_notifications = gtk.CheckButton(_("Enable notifications")) |
68 | 153 | self.enable_notifications.connect("toggled", self.option_toggled,'option-notifications') | 160 | self.enable_notifications.connect("toggled", self.option_toggled,'option-notifications') |
69 | @@ -178,6 +185,7 @@ | |||
70 | 178 | options_box.pack_start(self.disable_https,False,False,0) | 185 | options_box.pack_start(self.disable_https,False,False,0) |
71 | 179 | options_box.pack_start(self.ignore_activity,False,False,0) | 186 | options_box.pack_start(self.ignore_activity,False,False,0) |
72 | 180 | options_box.pack_start(self.api_retweet,False,False,0) | 187 | options_box.pack_start(self.api_retweet,False,False,0) |
73 | 188 | options_box.pack_start(self.expand_long_dents,False,False,0) | ||
74 | 181 | options_box.pack_start(self.open_fullscreen,False,False,0) | 189 | options_box.pack_start(self.open_fullscreen,False,False,0) |
75 | 182 | 190 | ||
76 | 183 | #does the app have notifications? | 191 | #does the app have notifications? |
77 | @@ -296,6 +304,9 @@ | |||
78 | 296 | def set_api_retweet(self,boolean): | 304 | def set_api_retweet(self,boolean): |
79 | 297 | self.api_retweet.set_active(boolean) | 305 | self.api_retweet.set_active(boolean) |
80 | 298 | 306 | ||
81 | 307 | def set_expand_long_dents(self,boolean): | ||
82 | 308 | self.expand_long_dents.set_active(boolean) | ||
83 | 309 | |||
84 | 299 | #More Code for notifications | 310 | #More Code for notifications |
85 | 300 | def set_notifications(self,boolean): | 311 | def set_notifications(self,boolean): |
86 | 301 | self.enable_notifications.set_active(boolean) | 312 | self.enable_notifications.set_active(boolean) |
87 | 302 | 313 | ||
88 | === modified file 'XMLProcessor.py' | |||
89 | --- XMLProcessor.py 2012-07-16 22:36:42 +0000 | |||
90 | +++ XMLProcessor.py 2013-08-31 16:29:00 +0000 | |||
91 | @@ -142,6 +142,29 @@ | |||
92 | 142 | #what server is this shit from? | 142 | #what server is this shit from? |
93 | 143 | profile_url = self.get_node_text(status,"statusnet:profile_url") | 143 | profile_url = self.get_node_text(status,"statusnet:profile_url") |
94 | 144 | dict['profile_url'] = profile_url | 144 | dict['profile_url'] = profile_url |
95 | 145 | |||
96 | 146 | # put attachments in a neat array if there are any | ||
97 | 147 | attachments = status.getElementsByTagName('attachments') | ||
98 | 148 | if attachments.length: | ||
99 | 149 | enclosures = attachments[0].getElementsByTagName('enclosure') | ||
100 | 150 | dict['attachments'] = [] | ||
101 | 151 | for i in range(enclosures.length): | ||
102 | 152 | item = enclosures.item(i) | ||
103 | 153 | a = { 'mimetype': item.getAttribute('mimetype'), | ||
104 | 154 | 'url': item.getAttribute('url')} | ||
105 | 155 | size_str = item.getAttribute('size') | ||
106 | 156 | if size_str.isdigit(): | ||
107 | 157 | a['size'] = int(size_str) | ||
108 | 158 | dict['attachments'].append(a) | ||
109 | 159 | |||
110 | 160 | # this should say if dent is truncated... but doesn't | ||
111 | 161 | #dict['truncated'] = self.get_node_text(status, "truncated") | ||
112 | 162 | # this is what actually works (fugly hack!) | ||
113 | 163 | sn_html = self.get_node_text(status, "statusnet:html") | ||
114 | 164 | dict['truncated'] = False | ||
115 | 165 | if sn_html.find("class=\"attachment more\" title=\"Show more\"") != -1: | ||
116 | 166 | dict['truncated'] = True | ||
117 | 167 | |||
118 | 145 | # we should clean the source ( if there is one ) | 168 | # we should clean the source ( if there is one ) |
119 | 146 | if dict['source']!=None: | 169 | if dict['source']!=None: |
120 | 147 | dict['source']=self.re_source_sub.sub( '', dict['source']) | 170 | dict['source']=self.re_source_sub.sub( '', dict['source']) |
121 | 148 | 171 | ||
122 | === modified file 'heybuddy.py' | |||
123 | --- heybuddy.py 2013-01-15 00:33:09 +0000 | |||
124 | +++ heybuddy.py 2013-08-31 16:29:00 +0000 | |||
125 | @@ -33,6 +33,7 @@ | |||
126 | 33 | import re | 33 | import re |
127 | 34 | import time | 34 | import time |
128 | 35 | import subprocess | 35 | import subprocess |
129 | 36 | import HTMLParser | ||
130 | 36 | #this might be on Maemo | 37 | #this might be on Maemo |
131 | 37 | from PlatformSpecific import has_hildon,links_unavailable | 38 | from PlatformSpecific import has_hildon,links_unavailable |
132 | 38 | #what are the custom classes that I need? | 39 | #what are the custom classes that I need? |
133 | @@ -137,7 +138,10 @@ | |||
134 | 137 | self.regex_group = re.compile("(^| )!([\w-]+)") | 138 | self.regex_group = re.compile("(^| )!([\w-]+)") |
135 | 138 | self.regex_user=re.compile("(^|[^A-z0-9])@(\w+)") | 139 | self.regex_user=re.compile("(^|[^A-z0-9])@(\w+)") |
136 | 139 | self.regex_just_user=re.compile("@(\w+)") | 140 | self.regex_just_user=re.compile("@(\w+)") |
138 | 140 | self.regex_url=re.compile("(http[s]?://.*?)(\.$|\. |\s|$)",re.IGNORECASE) | 141 | self.regex_url=re.compile("(http[s]?://.*?)(\.$|\. |\s|\)|$)",re.IGNORECASE) |
139 | 142 | #regex's for parsing html attachments | ||
140 | 143 | self.regex_find_body = re.compile("\<body\>(.*)\<\/body\>") | ||
141 | 144 | self.regex_remove_tags = re.compile('<[^>]*>') | ||
142 | 141 | #get the initial dents | 145 | #get the initial dents |
143 | 142 | self.initial_dents = self.conf.get('settings','initial_dents',default='20' ) | 146 | self.initial_dents = self.conf.get('settings','initial_dents',default='20' ) |
144 | 143 | self.dent_limit = int(self.initial_dents)*2 | 147 | self.dent_limit = int(self.initial_dents)*2 |
145 | @@ -187,12 +191,16 @@ | |||
146 | 187 | self.comm.connect('verify_credentialsXML',self.process_verifycredentialsXML) | 191 | self.comm.connect('verify_credentialsXML',self.process_verifycredentialsXML) |
147 | 188 | self.comm.connect('configXML',self.process_configXML) | 192 | self.comm.connect('configXML',self.process_configXML) |
148 | 189 | self.comm.connect('shortened_url',self.shortened_url) | 193 | self.comm.connect('shortened_url',self.shortened_url) |
149 | 194 | self.comm.connect('attachment-received',self.attachment_received) | ||
150 | 190 | #are we disabling https? | 195 | #are we disabling https? |
151 | 191 | self.comm.set_disable_https( self.conf.get_bool_option('disable_https') ) | 196 | self.comm.set_disable_https( self.conf.get_bool_option('disable_https') ) |
152 | 192 | #create an image cacher thingy | 197 | #create an image cacher thingy |
153 | 193 | self.imagecache = ImageCache() | 198 | self.imagecache = ImageCache() |
154 | 194 | self.imagecache.set_disabled( self.conf.get_bool_option('no_avatars') ) | 199 | self.imagecache.set_disabled( self.conf.get_bool_option('no_avatars') ) |
155 | 195 | self.imagecache.connect('get-widget-image', self.get_widget_image) | 200 | self.imagecache.connect('get-widget-image', self.get_widget_image) |
156 | 201 | |||
157 | 202 | # keep track of dents to notify of updated attachments | ||
158 | 203 | self.dent_map = {} | ||
159 | 196 | 204 | ||
160 | 197 | #Create notify-er if has pynotify | 205 | #Create notify-er if has pynotify |
161 | 198 | if has_pynotify: | 206 | if has_pynotify: |
162 | @@ -339,6 +347,8 @@ | |||
163 | 339 | self.settingspage.set_no_avatars( self.options['no_avatar'] ) | 347 | self.settingspage.set_no_avatars( self.options['no_avatar'] ) |
164 | 340 | self.options['api_retweet'] = self.conf.get_bool_option('api_retweet') | 348 | self.options['api_retweet'] = self.conf.get_bool_option('api_retweet') |
165 | 341 | self.settingspage.set_api_retweet( self.options['api_retweet'] ) | 349 | self.settingspage.set_api_retweet( self.options['api_retweet'] ) |
166 | 350 | self.options['expand_long_dents'] = self.conf.get_bool_option('expand_long_dents') | ||
167 | 351 | self.settingspage.set_expand_long_dents( self.options['expand_long_dents'] ) | ||
168 | 342 | self.options['notifications']= self.conf.get_bool_option('notifications') | 352 | self.options['notifications']= self.conf.get_bool_option('notifications') |
169 | 343 | self.settingspage.set_notifications( self.options['notifications'] ) | 353 | self.settingspage.set_notifications( self.options['notifications'] ) |
170 | 344 | self.options['notify_replies']= self.conf.get_bool_option('notify_replies') | 354 | self.options['notify_replies']= self.conf.get_bool_option('notify_replies') |
171 | @@ -355,6 +365,7 @@ | |||
172 | 355 | self.settingspage.connect('option-context-backwards',self.option_changed, 'context_backwards') | 365 | self.settingspage.connect('option-context-backwards',self.option_changed, 'context_backwards') |
173 | 356 | self.settingspage.connect('option-no-avatars',self.option_changed, 'no_avatars') | 366 | self.settingspage.connect('option-no-avatars',self.option_changed, 'no_avatars') |
174 | 357 | self.settingspage.connect('option-api-retweet', self.option_changed, 'api_retweet') | 367 | self.settingspage.connect('option-api-retweet', self.option_changed, 'api_retweet') |
175 | 368 | self.settingspage.connect('option-expand-long-dents', self.option_changed, 'expand_long_dents') | ||
176 | 358 | self.settingspage.connect('option-notifications',self.option_changed, 'notifications') | 369 | self.settingspage.connect('option-notifications',self.option_changed, 'notifications') |
177 | 359 | self.settingspage.connect('option-notify-replies',self.option_changed, 'notify_replies') | 370 | self.settingspage.connect('option-notify-replies',self.option_changed, 'notify_replies') |
178 | 360 | self.settingspage.connect('option-ignore-activity',self.option_changed, 'ignore_activity') | 371 | self.settingspage.connect('option-ignore-activity',self.option_changed, 'ignore_activity') |
179 | @@ -822,6 +833,14 @@ | |||
180 | 822 | dent.connect('favorite-clicked',self.favorite_clicked) | 833 | dent.connect('favorite-clicked',self.favorite_clicked) |
181 | 823 | dent.connect('unfavorite-clicked',self.unfavorite_clicked) | 834 | dent.connect('unfavorite-clicked',self.unfavorite_clicked) |
182 | 824 | dent.connect('open-link',self.open_link) | 835 | dent.connect('open-link',self.open_link) |
183 | 836 | |||
184 | 837 | # if dent was truncated, fetch the rest which | ||
185 | 838 | # should be in an html attachment | ||
186 | 839 | if self.options['expand_long_dents'] and data['truncated'] and 'attachments' in data: | ||
187 | 840 | for a in data['attachments']: | ||
188 | 841 | if a['mimetype'] == 'text/html': | ||
189 | 842 | self.fetch_attachment(dent, a['url']) | ||
190 | 843 | |||
191 | 825 | if target_page!=self.userpage: | 844 | if target_page!=self.userpage: |
192 | 826 | #get the image for this dent | 845 | #get the image for this dent |
193 | 827 | self.imagecache.add_image_to_widget(data['profile_image_url'],dent) | 846 | self.imagecache.add_image_to_widget(data['profile_image_url'],dent) |
194 | @@ -990,6 +1009,7 @@ | |||
195 | 990 | if not filtered_status: | 1009 | if not filtered_status: |
196 | 991 | #get the markup | 1010 | #get the markup |
197 | 992 | data['markup'] = self.markup_dent_text(data['text']) | 1011 | data['markup'] = self.markup_dent_text(data['text']) |
198 | 1012 | |||
199 | 993 | #did this dent connect | 1013 | #did this dent connect |
200 | 994 | if not self.connect_dent(data,target_page,is_direct_dent=is_direct): | 1014 | if not self.connect_dent(data,target_page,is_direct_dent=is_direct): |
201 | 995 | continue | 1015 | continue |
202 | @@ -1365,6 +1385,24 @@ | |||
203 | 1365 | 1385 | ||
204 | 1366 | def shortened_url(self, widget, url, old_url): | 1386 | def shortened_url(self, widget, url, old_url): |
205 | 1367 | self.mainwindow.shortened_url( url, old_url) | 1387 | self.mainwindow.shortened_url( url, old_url) |
206 | 1388 | |||
207 | 1389 | def fetch_attachment(self, dent, url): | ||
208 | 1390 | # if we aren't already fetching that url, then start fetching it | ||
209 | 1391 | if url not in self.dent_map: | ||
210 | 1392 | self.comm.fetch_attachment(url) | ||
211 | 1393 | self.dent_map[url] = [] | ||
212 | 1394 | # in any case add this dent widget to the list to be notified | ||
213 | 1395 | self.dent_map[url].append(dent) | ||
214 | 1396 | |||
215 | 1397 | def attachment_received(self, widget, html, url): | ||
216 | 1398 | # do some ugly HTML parsing | ||
217 | 1399 | h = HTMLParser.HTMLParser() | ||
218 | 1400 | text = self.regex_remove_tags.sub('', self.regex_find_body.findall(html)[0]) | ||
219 | 1401 | text = h.unescape(text) | ||
220 | 1402 | # notify all dent widgets with the updated text | ||
221 | 1403 | if url in self.dent_map: | ||
222 | 1404 | for dent in self.dent_map.pop(url): | ||
223 | 1405 | dent.update_text(self.markup_dent_text(text)) | ||
224 | 1368 | 1406 | ||
225 | 1369 | def remember_credentials(self, widget, remember): | 1407 | def remember_credentials(self, widget, remember): |
226 | 1370 | self.options['remember_credentials'] = remember | 1408 | self.options['remember_credentials'] = remember |
Uh oh, this sounds like a "feature". Because this requires adding a new module and making an extra http request, there needs to be a preference option to enable this (it should be disabled by default).