Merge lp:~submarine/ubuntu-scopes/openweathermap-previews into lp:~submarine/ubuntu-scopes/openweathermap

Proposed by David Callé
Status: Merged
Approved by: Michal Hruby
Approved revision: 24
Merged at revision: 21
Proposed branch: lp:~submarine/ubuntu-scopes/openweathermap-previews
Merge into: lp:~submarine/ubuntu-scopes/openweathermap
Diff against target: 313 lines (+187/-27)
3 files modified
data/openweathermap.scope.in (+1/-1)
src/unity_openweathermap_daemon.py (+184/-24)
tests/test_openweathermap.py (+2/-2)
To merge this branch: bzr merge lp:~submarine/ubuntu-scopes/openweathermap-previews
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Michal Hruby (community) Approve
Review via email: mp+155729@code.launchpad.net

Commit message

Initial previews (with Flickr weather project support)

Description of the change

Initial previews.
- Displays a geolocalized photo with matching weather (using Flickr weather project)
- If no photo is found, a "Submit photo" button appears, opening the Flickr weather project group.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote :

From a quick test it looks and works great! :)

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/openweathermap.scope.in'
--- data/openweathermap.scope.in 2013-03-15 17:29:42 +0000
+++ data/openweathermap.scope.in 2013-03-27 13:24:21 +0000
@@ -4,7 +4,7 @@
4Icon=4Icon=
5_Keywords=openweathermap;weather;sky;forecast;5_Keywords=openweathermap;weather;sky;forecast;
6RequiredMetadata=6RequiredMetadata=
7OptionalMetadata=7OptionalMetadata=min_temp[s];max_temp[s];pressure[s];humidity[s];wind_speed[s];wind_direction[s];latitude[s];longitude[s];
8Loader=/usr/share/unity-scopes/openweathermap/unity_openweathermap_daemon.py8Loader=/usr/share/unity-scopes/openweathermap/unity_openweathermap_daemon.py
9RemoteContent=true9RemoteContent=true
10Type=info10Type=info
1111
=== modified file 'src/unity_openweathermap_daemon.py'
--- src/unity_openweathermap_daemon.py 2013-03-21 18:00:25 +0000
+++ src/unity_openweathermap_daemon.py 2013-03-27 13:24:21 +0000
@@ -21,6 +21,7 @@
21import json21import json
22import datetime22import datetime
23import gettext23import gettext
24from random import randrange
2425
25APP_NAME = 'unity-scope-openweathermap'26APP_NAME = 'unity-scope-openweathermap'
26LOCAL_PATH = '/usr/share/locale/'27LOCAL_PATH = '/usr/share/locale/'
@@ -39,7 +40,7 @@
39PROVIDER_ICON = SVG_DIR+'service-openweathermap.svg'40PROVIDER_ICON = SVG_DIR+'service-openweathermap.svg'
40DEFAULT_RESULT_ICON = SVG_DIR+'result-info.svg'41DEFAULT_RESULT_ICON = SVG_DIR+'result-info.svg'
41DEFAULT_RESULT_MIMETYPE = 'text/html'42DEFAULT_RESULT_MIMETYPE = 'text/html'
42DEFAULT_RESULT_TYPE = Unity.ResultType.PERSONAL43DEFAULT_RESULT_TYPE = Unity.ResultType.DEFAULT
4344
44c1 = {'id' :'weather',45c1 = {'id' :'weather',
45 'name' :_('Weather Forecast'),46 'name' :_('Weather Forecast'),
@@ -47,13 +48,37 @@
47 'renderer':Unity.CategoryRenderer.VERTICAL_TILE}48 'renderer':Unity.CategoryRenderer.VERTICAL_TILE}
48CATEGORIES = [c1]49CATEGORIES = [c1]
49FILTERS = []50FILTERS = []
50EXTRA_METADATA = []51m1 = {'id' :'min_temp',
52 'type' :'s',
53 'field':Unity.SchemaFieldType.OPTIONAL}
54m2 = {'id' :'max_temp',
55 'type' :'s',
56 'field':Unity.SchemaFieldType.OPTIONAL}
57m3 = {'id' :'pressure',
58 'type' :'s',
59 'field':Unity.SchemaFieldType.OPTIONAL}
60m4 = {'id' :'humidity',
61 'type' :'s',
62 'field':Unity.SchemaFieldType.OPTIONAL}
63m5 = {'id' :'wind_speed',
64 'type' :'s',
65 'field':Unity.SchemaFieldType.OPTIONAL}
66m6 = {'id' :'wind_direction',
67 'type' :'s',
68 'field':Unity.SchemaFieldType.OPTIONAL}
69m7 = {'id' :'latitude',
70 'type' :'s',
71 'field':Unity.SchemaFieldType.OPTIONAL}
72m8 = {'id' :'longitude',
73 'type' :'s',
74 'field':Unity.SchemaFieldType.OPTIONAL}
75EXTRA_METADATA = [m1, m2, m3, m4, m5, m6, m7, m8]
5176
52def weather_search(query, s_type):77def weather_search(query, s_type):
53 print (query)78 print (query)
54 query = urllib.parse.quote(str(query))79 query = urllib.parse.quote(str(query))
55 data = None80 data = None
56 if not query:81 if not query or len(query) <= 1:
57 return data82 return data
58 if s_type == 'forecast':83 if s_type == 'forecast':
59 uri = "%s%s?mode=daily_compact&units=metric" % (SEARCH_URI[1], query)84 uri = "%s%s?mode=daily_compact&units=metric" % (SEARCH_URI[1], query)
@@ -113,10 +138,30 @@
113 wind = place_data['list'][0]['wind']['speed']138 wind = place_data['list'][0]['wind']['speed']
114 temp_c = float(place_data['list'][0]['main']['temp'])139 temp_c = float(place_data['list'][0]['main']['temp'])
115 temp_f = temp_c*(9.0/5.0)+32140 temp_f = temp_c*(9.0/5.0)+32
116 temp = '%i%sC/%i%sF' % (int(temp_c), u"\u00B0", int(temp_f), u"\u00B0")141 temp = '%i%sC / %i%sF' % (int(temp_c), u"\u00B0", int(temp_f), u"\u00B0")
117 title = _('Today') + '\n' + temp142 name = place_data['list'][0]['name']
143 country = place_data['list'][0]['sys']['country']
144 title = name + ', ' + country + '\n' + temp
118 city_id = place_data['list'][0]['id']145 city_id = place_data['list'][0]['id']
119 uri = place_data['list'][0]['url']146 uri = place_data['list'][0]['url']
147 min_temp_c = float(place_data['list'][0]['main']['temp_min'])
148 min_temp_f = min_temp_c*(9.0/5.0)+32
149 min_temp = '%i%sC / %i%sF' % (int(min_temp_c), u"\u00B0", int(min_temp_f), u"\u00B0")
150 max_temp_c = float(place_data['list'][0]['main']['temp_max'])
151 max_temp_f = max_temp_c*(9.0/5.0)+32
152 max_temp = '%i%sC / %i%sF' % (int(max_temp_c), u"\u00B0", int(max_temp_f), u"\u00B0")
153 try:
154 pressure = place_data['list'][0]['main']['pressure']
155 except:
156 pressure = ''
157 try:
158 humidity = place_data['list'][0]['main']['humidity']
159 except:
160 humidity = ''
161 wind_speed = place_data['list'][0]['wind']['speed']
162 wind_direction = place_data['list'][0]['wind']['deg']
163 latitude = place_data['list'][0]['coord']['lat']
164 longitude = place_data['list'][0]['coord']['lon']
120 except Exception as error:165 except Exception as error:
121 print(error)166 print(error)
122 return results167 return results
@@ -125,7 +170,15 @@
125 results.append({'uri':uri,170 results.append({'uri':uri,
126 'icon':icon,171 'icon':icon,
127 'title':title,172 'title':title,
128 'comment':description})173 'comment':description,
174 'min_temp':GLib.Variant('s', min_temp),
175 'max_temp':GLib.Variant('s', max_temp),
176 'pressure':GLib.Variant('s', str(pressure)),
177 'humidity':GLib.Variant('s', str(humidity)),
178 'wind_speed':GLib.Variant('s', str(wind_speed)),
179 'wind_direction':GLib.Variant('s', str(wind_direction)),
180 'latitude':GLib.Variant('s', str(latitude)),
181 'longitude':GLib.Variant('s', str(longitude))})
129 forecast = weather_search(city_id, 'forecast')182 forecast = weather_search(city_id, 'forecast')
130 if not forecast or not "list" in forecast:183 if not forecast or not "list" in forecast:
131 return results184 return results
@@ -140,18 +193,35 @@
140 try:193 try:
141 description = forecast['list'][i]['weather'][0]['description']194 description = forecast['list'][i]['weather'][0]['description']
142 icon = get_icon(forecast['list'][i]['weather'][0]['icon'])195 icon = get_icon(forecast['list'][i]['weather'][0]['icon'])
143 wind = forecast['list'][i]['speed']
144 temp_c = float(forecast['list'][i]['temp'])196 temp_c = float(forecast['list'][i]['temp'])
145 temp_f = temp_c*(9.0/5.0)+32197 temp_f = temp_c*(9.0/5.0)+32
146 temp = '%i%sC/%i%sF' % (int(temp_c), u"\u00B0", int(temp_f), u"\u00B0")198 temp = '%i%sC / %i%sF' % (int(temp_c), u"\u00B0", int(temp_f), u"\u00B0")
147 title = day_name + '\n' + temp199 title = day_name + '\n' + temp
200 min_temp_c = float(forecast['list'][i]['morn'])
201 min_temp_f = min_temp_c*(9.0/5.0)+32
202 min_temp = '%i%sC / %i%sF' % (int(min_temp_c), u"\u00B0", int(min_temp_f), u"\u00B0")
203 max_temp_c = float(forecast['list'][i]['eve'])
204 max_temp_f = max_temp_c*(9.0/5.0)+32
205 max_temp = '%i%sC / %i%sF' % (int(max_temp_c), u"\u00B0", int(max_temp_f), u"\u00B0")
206 pressure = forecast['list'][i]['pressure']
207 humidity = forecast['list'][i]['humidity']
208 wind_speed = forecast['list'][i]['speed']
209 wind_direction = forecast['list'][i]['deg']
148 except Exception as error:210 except Exception as error:
149 print(error)211 print(error)
150 return results212 return results
151 results.append({'uri':uri+"#"+day_name,213 results.append({'uri':uri+"#"+day_name,
152 'icon':icon,214 'icon':icon,
153 'title':title,215 'title':title,
154 'comment':description})216 'comment':description,
217 'min_temp':GLib.Variant('s', min_temp),
218 'max_temp':GLib.Variant('s', max_temp),
219 'pressure':GLib.Variant('s', str(pressure)),
220 'humidity':GLib.Variant('s', str(humidity)),
221 'wind_speed':GLib.Variant('s', str(wind_speed)),
222 'wind_direction':GLib.Variant('s', str(wind_direction)),
223 'latitude':GLib.Variant('s', str(latitude)),
224 'longitude':GLib.Variant('s', str(longitude))})
155 return results225 return results
156226
157227
@@ -188,21 +258,97 @@
188 i['comment'] = ''258 i['comment'] = ''
189 if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':259 if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':
190 i['dnd_uri'] = i['uri']260 i['dnd_uri'] = i['uri']
191 i['metadata'] = {}261 i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
192 if EXTRA_METADATA:262 result_set.add_result(**i)
193 for e in i:263 except Exception as error:
194 for m in EXTRA_METADATA:264 print (error)
195 if m['id'] == e:265
196 i['metadata'][e] = i[e]266class Preview (Unity.ResultPreviewer):
197 i['metadata']['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)267
198 result = Unity.ScopeResult.create(str(i['uri']), str(i['icon']),268 def get_image(self,q, lat, lon):
199 i['category'], i['result_type'],269 print (lat, lon)
200 str(i['mimetype']), str(i['title']),270 flick_map={'weather-clear':'clear',
201 str(i['comment']), str(i['dnd_uri']),271 'weather-clear-night':'clear',
202 i['metadata'])272 'weather-few-clouds':'cloudy',
203 result_set.add_result(result)273 'weather-few-clouds-night':'cloudy',
204 except Exception as error:274 'weather-clouds':'cloudy',
205 print (error)275 'weather-clouds-night':'cloudy',
276 'weather-overcast':'cloudy',
277 'weather-overcast':'cloudy',
278 'weather-showers-scattered':'rain',
279 'weather-showers-scattered':'rain',
280 'weather-showers':'rain',
281 'weather-showers':'rain',
282 'weather-storm':'storm',
283 'weather-storm':'storm',
284 'weather-snow':'snow',
285 'weather-snow':'snow',
286 'weather-fog':'fog',
287 'weather-fog':'fog'}
288 license_list = ["All Rights Reserved",
289 "Attribution-NonCommercial-ShareAlike License",
290 "Attribution-NonCommercial License",
291 "Attribution-NonCommercial-NoDerivs License",
292 "Attribution License",
293 "Attribution-ShareAlike License",
294 "Attribution-NoDerivs License",
295 "No known copyright restrictions",
296 "United States Government Work"]
297 image = None
298 query = urllib.parse.quote(flick_map[q])
299 key = 'd87224f0b467093b2a87fd788d950e27'
300 uri = 'http://secure.flickr.com/services/rest/?method=flickr.photos.search&nojsoncallback=1&per_page=20&api_key=%s&extras=url_m,owner_name,license&group_id=1463451@N25&format=json&tag_mode=all&tags=%s&bbox=%f,%f,%f,%f' % (key,
301 query,
302 round(float(lon) - 0.1, 2), round(float(lat) - 0.1, 2),
303 round(float(lon) + 0.1, 2), round(float(lat) +0.1, 2))
304 print (uri)
305 try:
306 response = urllib.request.urlopen(uri).read()
307 data = json.loads(response.decode('utf-8'))
308 photo = randrange(len(data['photos']['photo']))
309 image = data['photos']['photo'][photo]['url_m']
310 owner = data['photos']['photo'][photo]['ownername']
311 license = license_list[int(data['photos']['photo'][photo]['license'])]
312 link = 'https://www.flickr.com/photos/%s/%s' % (data['photos']['photo'][photo]['owner'], data['photos']['photo'][photo]['id'])
313 except Exception as error:
314 print (error)
315 image, owner, license, link = None, None, None, None
316 return image, owner, license, link
317
318 def do_run(self):
319
320 preview = Unity.GenericPreview.new(self.result.title.split('\n')[0], '', None)
321 preview.props.subtitle = self.result.comment.capitalize()
322 image, owner, license, link = self.get_image(self.result.icon_hint,
323 self.result.metadata['latitude'].get_string(),
324 self.result.metadata['longitude'].get_string())
325
326 gfile_icon = Gio.file_new_for_path(PROVIDER_ICON)
327 gicon = Gio.FileIcon.new (gfile_icon)
328 open_action = Unity.PreviewAction.new("open", _("Open Weather Map"), gicon)
329 preview.add_action(open_action)
330 preview.add_info(Unity.InfoHint.new("min_temp", _("Minimum Temperature"), None, self.result.metadata['min_temp'].get_string()))
331 preview.add_info(Unity.InfoHint.new("max_temp", _("Maximum Temperature"), None, self.result.metadata['max_temp'].get_string()))
332 preview.add_info(Unity.InfoHint.new("wind_speed", _("Wind Speed"), None, self.result.metadata['wind_speed'].get_string() + ' m/s'))
333 preview.add_info(Unity.InfoHint.new("wind_direction", _("Wind Direction"), None, self.result.metadata['wind_direction'].get_string() + u"\u00B0"))
334 if self.result.metadata['pressure'].get_string() != '':
335 preview.add_info(Unity.InfoHint.new("pressure", _("Pressure"), None, self.result.metadata['pressure'].get_string() + ' hPa'))
336 if self.result.metadata['humidity'].get_string() != '':
337 preview.add_info(Unity.InfoHint.new("humidity", _("Humidity"), None, self.result.metadata['humidity'].get_string() + '%'))
338 if image:
339 preview.props.image_source_uri = image
340 gfile_icon = Gio.file_new_for_path(SVG_DIR+'service-flickr.svg')
341 gicon = Gio.FileIcon.new (gfile_icon)
342 preview.add_info(Unity.InfoHint.new("photo_owner", _("Photo source"), gicon, 'Flickr'))
343 preview.add_info(Unity.InfoHint.new("photo_owner", _("Photo credit"), None, owner))
344 preview.add_info(Unity.InfoHint.new("photo_license", _("Photo license"), None, license))
345 else:
346 gfile_icon = Gio.file_new_for_path(SVG_DIR+'service-flickr.svg')
347 gicon = Gio.FileIcon.new (gfile_icon)
348 submit_action = Unity.PreviewAction.new("submit", _("Submit Photo"), gicon)
349 preview.add_action(submit_action)
350 return preview
351
206352
207class Scope (Unity.AbstractScope):353class Scope (Unity.AbstractScope):
208 def __init__(self):354 def __init__(self):
@@ -255,5 +401,19 @@
255 se = MySearch (search_context)401 se = MySearch (search_context)
256 return se402 return se
257403
404 def do_create_previewer(self, result, metadata):
405 rp = Preview()
406 rp.set_scope_result(result)
407 rp.set_search_metadata(metadata)
408 return rp
409
410 def do_activate(self, result, metadata, id):
411 if not id:
412 return Unity.ActivationResponse(handled=Unity.HandledType.SHOW_PREVIEW, goto_uri=result.uri)
413 if id == 'submit':
414 uri = 'https://www.flickr.com/groups/projectweather/'
415 return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri=uri)
416 return
417
258def load_scope():418def load_scope():
259 return Scope()419 return Scope()
260420
=== modified file 'tests/test_openweathermap.py'
--- tests/test_openweathermap.py 2013-03-21 18:20:20 +0000
+++ tests/test_openweathermap.py 2013-03-27 13:24:21 +0000
@@ -43,11 +43,11 @@
43 'file:tests/data/mock_openweathermap_city_pass#']43 'file:tests/data/mock_openweathermap_city_pass#']
44 expected_results = ['http://openweathermap.org/city/3026083', 44 expected_results = ['http://openweathermap.org/city/3026083',
45 'weather-snow',45 'weather-snow',
46 'Today\n0°C/33°F',46 'Chatillon, FR\n0°C / 33°F',
47 'heavy snow',47 'heavy snow',
48 'http://openweathermap.org/city/3026083#Tomorrow',48 'http://openweathermap.org/city/3026083#Tomorrow',
49 'weather-clouds',49 'weather-clouds',
50 'Tomorrow\n257°C/494°F',50 'Tomorrow\n257°C / 494°F',
51 'scattered clouds']51 'scattered clouds']
52 results = []52 results = []
53 for s in ['query']:53 for s in ['query']:

Subscribers

People subscribed via source and target branches

to all changes: