Merge lp:~mhr3/unity-lens-video/fix-1226573 into lp:unity-lens-video
- fix-1226573
- Merge into trunk
Proposed by
Michal Hruby
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Paweł Stołowski | ||||||||
Approved revision: | 124 | ||||||||
Merged at revision: | 121 | ||||||||
Proposed branch: | lp:~mhr3/unity-lens-video/fix-1226573 | ||||||||
Merge into: | lp:unity-lens-video | ||||||||
Diff against target: |
811 lines (+210/-355) 7 files modified
debian/control (+0/-1) src/Makefile.am (+0/-1) src/remote-scope.vala (+191/-273) src/remote-uri.vala (+0/-52) src/remote-video-main.vala (+11/-24) src/ubuntu-video-search.vala (+8/-3) tests/unit/Makefile.am (+0/-1) |
||||||||
To merge this branch: | bzr merge lp:~mhr3/unity-lens-video/fix-1226573 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Stołowski (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+186020@code.launchpad.net |
Commit message
Simplify the scope, use the non-deprecated API, and pass a form-factor hint to the server.
Description of the change
Simplify the scope, use the non-deprecated API, and pass a form-factor hint to the server.
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote : | # |
Looks good and works, but the whole business with RESULT_
review:
Needs Fixing
Revision history for this message
Paweł Stołowski (stolowski) wrote : | # |
After discussing this on IRC, it's better to leave it for now as it can potentially break the behavior of current Unity8 shell.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/control' | |||
2 | --- debian/control 2013-07-04 08:32:52 +0000 | |||
3 | +++ debian/control 2013-09-17 12:19:35 +0000 | |||
4 | @@ -35,7 +35,6 @@ | |||
5 | 35 | Architecture: any | 35 | Architecture: any |
6 | 36 | Depends: ${misc:Depends}, | 36 | Depends: ${misc:Depends}, |
7 | 37 | ${shlibs:Depends}, | 37 | ${shlibs:Depends}, |
8 | 38 | gvfs-bin, | ||
9 | 39 | Enhances: unity-lens-video | 38 | Enhances: unity-lens-video |
10 | 40 | Description: Remote videos engine | 39 | Description: Remote videos engine |
11 | 41 | This scope adds a remote videos search engine to the Video lens. | 40 | This scope adds a remote videos search engine to the Video lens. |
12 | 42 | 41 | ||
13 | === modified file 'src/Makefile.am' | |||
14 | --- src/Makefile.am 2013-06-20 16:13:59 +0000 | |||
15 | +++ src/Makefile.am 2013-09-17 12:19:35 +0000 | |||
16 | @@ -95,7 +95,6 @@ | |||
17 | 95 | remote-scope-globals.vala \ | 95 | remote-scope-globals.vala \ |
18 | 96 | remote-video-main.vala \ | 96 | remote-video-main.vala \ |
19 | 97 | remote-scope.vala \ | 97 | remote-scope.vala \ |
20 | 98 | remote-uri.vala \ | ||
21 | 99 | ubuntu-video-search.vala \ | 98 | ubuntu-video-search.vala \ |
22 | 100 | utils.vala \ | 99 | utils.vala \ |
23 | 101 | video-file.vala \ | 100 | video-file.vala \ |
24 | 102 | 101 | ||
25 | === modified file 'src/remote-scope.vala' | |||
26 | --- src/remote-scope.vala 2013-06-20 16:13:59 +0000 | |||
27 | +++ src/remote-scope.vala 2013-09-17 12:19:35 +0000 | |||
28 | @@ -22,14 +22,15 @@ | |||
29 | 22 | 22 | ||
30 | 23 | namespace Unity.VideoLens | 23 | namespace Unity.VideoLens |
31 | 24 | { | 24 | { |
33 | 25 | public class RemoteVideoScope : Unity.DeprecatedScope | 25 | public class RemoteVideoScope : Unity.SimpleScope |
34 | 26 | { | 26 | { |
39 | 27 | private static int REFRESH_INTERVAL = 3600; // fetch sources & recommendations once an hour | 27 | private const int REFRESH_INTERVAL = 3600; // fetch sources & recommendations once an hour |
40 | 28 | private static int RETRY_INTERVAL = 60; // retry sources/recommendations after a minute | 28 | private const int RETRY_INTERVAL = 60; // retry sources/recommendations after a minute |
41 | 29 | 29 | ||
42 | 30 | private static string PREVIEW_ON_LMB = "lmb-preview"; | 30 | private const string RESULT_PREVIEW_ON_LMB = "lmb-preview"; |
43 | 31 | private const string RESULT_DETAILS_URI = "details-uri"; | ||
44 | 32 | |||
45 | 31 | private Soup.Session session; | 33 | private Soup.Session session; |
46 | 32 | private PreferencesManager preferences = PreferencesManager.get_default (); | ||
47 | 33 | Gee.ArrayList<RemoteVideoFile?> recommendations; | 34 | Gee.ArrayList<RemoteVideoFile?> recommendations; |
48 | 34 | int64 recommendations_last_update = 0; | 35 | int64 recommendations_last_update = 0; |
49 | 35 | Zeitgeist.DataSourceRegistry zg_sources; | 36 | Zeitgeist.DataSourceRegistry zg_sources; |
50 | @@ -37,14 +38,18 @@ | |||
51 | 37 | 38 | ||
52 | 38 | public RemoteVideoScope () | 39 | public RemoteVideoScope () |
53 | 39 | { | 40 | { |
55 | 40 | Object (dbus_path: "/net/launchpad/scope/remotevideos", id: "video-remote.scope"); | 41 | Object (unique_name: "/net/launchpad/scope/remotevideos", |
56 | 42 | group_name: "net.launchpad.scope.RemoteVideos"); | ||
57 | 41 | } | 43 | } |
58 | 42 | 44 | ||
59 | 43 | protected override void constructed () | 45 | protected override void constructed () |
60 | 44 | { | 46 | { |
61 | 45 | base.constructed (); | 47 | base.constructed (); |
62 | 46 | 48 | ||
64 | 47 | schema.add_field (PREVIEW_ON_LMB, "b", Unity.Schema.FieldType.OPTIONAL); | 49 | var schema = new Unity.Schema (); |
65 | 50 | schema.add_field (RESULT_PREVIEW_ON_LMB, "b", Unity.Schema.FieldType.OPTIONAL); | ||
66 | 51 | schema.add_field (RESULT_DETAILS_URI, "s", Unity.Schema.FieldType.OPTIONAL); | ||
67 | 52 | this.schema = schema; | ||
68 | 48 | 53 | ||
69 | 49 | recommendations = new Gee.ArrayList<RemoteVideoFile?> (); | 54 | recommendations = new Gee.ArrayList<RemoteVideoFile?> (); |
70 | 50 | 55 | ||
71 | @@ -65,39 +70,18 @@ | |||
72 | 65 | session.user_agent = "Unity Video Lens Remote Scope v" + Config.VERSION; | 70 | session.user_agent = "Unity Video Lens Remote Scope v" + Config.VERSION; |
73 | 66 | session.add_feature_by_type (typeof (SoupGNOME.ProxyResolverGNOME)); | 71 | session.add_feature_by_type (typeof (SoupGNOME.ProxyResolverGNOME)); |
74 | 67 | 72 | ||
75 | 68 | search_in_global = false; | ||
76 | 69 | search_changed.connect ((search, search_type, cancellable) => | ||
77 | 70 | { | ||
78 | 71 | update_search_async.begin (search, search_type, cancellable); | ||
79 | 72 | }); | ||
80 | 73 | |||
81 | 74 | generate_search_key.connect ((scope, search) => | ||
82 | 75 | { | ||
83 | 76 | return search.search_string.strip (); | ||
84 | 77 | }); | ||
85 | 78 | |||
86 | 79 | preferences.notify["remote-content-search"].connect ((obj, pspec) => | ||
87 | 80 | { | ||
88 | 81 | queue_search_changed (SearchType.DEFAULT); | ||
89 | 82 | }); | ||
90 | 83 | |||
91 | 84 | populate_categories (); | 73 | populate_categories (); |
92 | 85 | query_list_of_sources (); | ||
93 | 86 | 74 | ||
95 | 87 | // refresh the at least once every 30 minutes | 75 | // refresh the search at least once every 30 minutes |
96 | 88 | GLib.Timeout.add_seconds (REFRESH_INTERVAL/2, () => | 76 | GLib.Timeout.add_seconds (REFRESH_INTERVAL/2, () => |
97 | 89 | { | 77 | { |
99 | 90 | queue_search_changed (SearchType.DEFAULT); return true; | 78 | results_invalidated (SearchType.DEFAULT); |
100 | 79 | return true; | ||
101 | 91 | }); | 80 | }); |
102 | 92 | 81 | ||
111 | 93 | try | 82 | set_search_async_func (dispatch_search); |
112 | 94 | { | 83 | set_preview_async_func (dispatch_preview); |
113 | 95 | export (); | 84 | set_activate_func (activate_result); |
106 | 96 | } | ||
107 | 97 | catch (Error e) | ||
108 | 98 | { | ||
109 | 99 | error ("Failed to export scope: %s", e.message); | ||
110 | 100 | } | ||
114 | 101 | } | 85 | } |
115 | 102 | 86 | ||
116 | 103 | private void populate_categories () | 87 | private void populate_categories () |
117 | @@ -108,121 +92,89 @@ | |||
118 | 108 | categories.add(new Unity.Category ("online", _("Online"), new FileIcon (icon_dir.get_child ("group-internet.svg")), Unity.CategoryRenderer.VERTICAL_TILE)); | 92 | categories.add(new Unity.Category ("online", _("Online"), new FileIcon (icon_dir.get_child ("group-internet.svg")), Unity.CategoryRenderer.VERTICAL_TILE)); |
119 | 109 | categories.add(new Unity.Category ("more", _("More suggestions"), new FileIcon (icon_dir.get_child ("group-treat-yourself.svg")), Unity.CategoryRenderer.VERTICAL_TILE)); | 93 | categories.add(new Unity.Category ("more", _("More suggestions"), new FileIcon (icon_dir.get_child ("group-treat-yourself.svg")), Unity.CategoryRenderer.VERTICAL_TILE)); |
120 | 110 | 94 | ||
122 | 111 | this.categories = categories; | 95 | this.category_set = categories; |
123 | 96 | } | ||
124 | 97 | |||
125 | 98 | private void dispatch_search (ScopeSearchBase search, | ||
126 | 99 | ScopeSearchBaseCallback cb) | ||
127 | 100 | { | ||
128 | 101 | perform_search.begin (search, (obj, res) => | ||
129 | 102 | { | ||
130 | 103 | try | ||
131 | 104 | { | ||
132 | 105 | perform_search.end (res); | ||
133 | 106 | } | ||
134 | 107 | catch (Error err) | ||
135 | 108 | { | ||
136 | 109 | warning ("Unable to perform search: %s", err.message); | ||
137 | 110 | } | ||
138 | 111 | cb (search); | ||
139 | 112 | }); | ||
140 | 113 | } | ||
141 | 114 | |||
142 | 115 | private void dispatch_preview (ResultPreviewer previewer, | ||
143 | 116 | AbstractPreviewCallback cb) | ||
144 | 117 | { | ||
145 | 118 | preview_result.begin (previewer.result, (obj, res) => | ||
146 | 119 | { | ||
147 | 120 | var preview = preview_result.end (res); | ||
148 | 121 | cb (previewer, preview); | ||
149 | 122 | }); | ||
150 | 123 | } | ||
151 | 124 | |||
152 | 125 | public override string normalize_search_query (string search_query) | ||
153 | 126 | { | ||
154 | 127 | return search_query.strip (); | ||
155 | 112 | } | 128 | } |
156 | 113 | 129 | ||
157 | 114 | /* Query the server for a list of sources that will be used | 130 | /* Query the server for a list of sources that will be used |
158 | 115 | * to build sources filter options and search queries. | 131 | * to build sources filter options and search queries. |
159 | 116 | */ | 132 | */ |
221 | 117 | private void query_list_of_sources () | 133 | private async void query_list_of_sources () |
222 | 118 | { | 134 | { |
223 | 119 | var msg = new Soup.Message ("GET", UbuntuVideoSearch.sources_uri ()); | 135 | try |
224 | 120 | session.queue_message (msg, sources_cb); | 136 | { |
225 | 121 | } | 137 | var sources_msg = new Soup.Message ("GET", UbuntuVideoSearch.sources_uri ()); |
226 | 122 | 138 | var msg = yield queue_soup_message (sources_msg); | |
227 | 123 | private Gee.ArrayList<RemoteVideoFile?>? handle_search_response (Soup.Message msg, bool is_treat_yourself = false) | 139 | var sources_array = UbuntuVideoSearch.process_sources_results ((string) msg.response_body.data); |
228 | 124 | { | 140 | // FIXME: do something with the sources once we support dynamic filters |
229 | 125 | if (msg.status_code != 200) | 141 | } |
230 | 126 | { | 142 | catch (Error e) |
231 | 127 | warning ("Unable to get results from the server: %u, %s", msg.status_code, msg.reason_phrase); | 143 | { |
232 | 128 | } | 144 | warning ("Got invalid json from the server"); |
233 | 129 | else | 145 | } |
234 | 130 | { | 146 | |
235 | 131 | try | 147 | // refresh the sources after a while |
236 | 132 | { | 148 | GLib.Timeout.add_seconds (REFRESH_INTERVAL, () => |
237 | 133 | return UbuntuVideoSearch.process_search_results ((string)msg.response_body.data, is_treat_yourself); | 149 | { |
238 | 134 | } | 150 | query_list_of_sources.begin (); return false; |
178 | 135 | catch (Error e) | ||
179 | 136 | { | ||
180 | 137 | warning ("Error processing search results: %s", e.message); | ||
181 | 138 | } | ||
182 | 139 | } | ||
183 | 140 | return null; | ||
184 | 141 | } | ||
185 | 142 | |||
186 | 143 | private void sources_cb (Soup.Session session, Soup.Message msg) | ||
187 | 144 | { | ||
188 | 145 | uint interval = RETRY_INTERVAL; | ||
189 | 146 | if (msg.status_code != 200) | ||
190 | 147 | { | ||
191 | 148 | warning ("Unable to query the server for a list of sources, %u: %s", msg.status_code, msg.reason_phrase); | ||
192 | 149 | } | ||
193 | 150 | else | ||
194 | 151 | { | ||
195 | 152 | try | ||
196 | 153 | { | ||
197 | 154 | var sources_array = UbuntuVideoSearch.process_sources_results ((string) msg.response_body.data); | ||
198 | 155 | |||
199 | 156 | // remove all existing sources | ||
200 | 157 | var to_remove = new SList<string> (); | ||
201 | 158 | foreach (var opt in sources.options) | ||
202 | 159 | to_remove.append (opt.id); | ||
203 | 160 | foreach (var id in to_remove) | ||
204 | 161 | sources.remove_option (id); | ||
205 | 162 | |||
206 | 163 | // add sources | ||
207 | 164 | foreach (var src in sources_array) | ||
208 | 165 | { | ||
209 | 166 | sources.add_option (src, src, null); | ||
210 | 167 | } | ||
211 | 168 | interval = REFRESH_INTERVAL; | ||
212 | 169 | } | ||
213 | 170 | catch (Error e) | ||
214 | 171 | { | ||
215 | 172 | warning ("Got invalid json from the server"); | ||
216 | 173 | } | ||
217 | 174 | } | ||
218 | 175 | GLib.Timeout.add_seconds (interval, () => | ||
219 | 176 | { | ||
220 | 177 | query_list_of_sources (); return false; | ||
239 | 178 | }); | 151 | }); |
240 | 179 | } | 152 | } |
241 | 180 | 153 | ||
243 | 181 | public override async Unity.ActivationResponse? activate_result (ScopeResult result) | 154 | public Unity.ActivationResponse? activate_result (ScopeResult result, |
244 | 155 | SearchMetadata metadata, | ||
245 | 156 | string? action_id) | ||
246 | 182 | { | 157 | { |
248 | 183 | var realcat = result.metadata.lookup (PREVIEW_ON_LMB); | 158 | var realcat = result.metadata.lookup (RESULT_PREVIEW_ON_LMB); |
249 | 184 | // activation of More Suggestions should display a preview. | 159 | // activation of More Suggestions should display a preview. |
251 | 185 | if (realcat != null && realcat.get_boolean ()) | 160 | if (action_id == null && realcat != null && realcat.get_boolean ()) |
252 | 186 | { | 161 | { |
255 | 187 | var preview = yield preview_result (result); | 162 | return new Unity.ActivationResponse (Unity.HandledType.SHOW_PREVIEW); |
254 | 188 | return new Unity.ActivationResponse.with_preview (preview); | ||
256 | 189 | } | 163 | } |
257 | 190 | 164 | ||
259 | 191 | return on_activate_uri (result.uri); | 165 | return on_activate_uri (result); |
260 | 192 | } | 166 | } |
261 | 193 | 167 | ||
263 | 194 | private Unity.ActivationResponse on_activate_uri (string rawuri) | 168 | private Unity.ActivationResponse on_activate_uri (Unity.ScopeResult result) |
264 | 195 | { | 169 | { |
284 | 196 | var fakeuri = RemoteUri.from_rawuri (rawuri); | 170 | zeitgeist_insert_event (result.uri, result.title, result.icon_hint); |
285 | 197 | if (fakeuri != null) | 171 | // let unity open the uri for us |
267 | 198 | { | ||
268 | 199 | if (use_zeitgeist) | ||
269 | 200 | zeitgeist_insert_event (fakeuri.uri, fakeuri.title, fakeuri.icon); | ||
270 | 201 | try | ||
271 | 202 | { | ||
272 | 203 | GLib.AppInfo.launch_default_for_uri (fakeuri.uri, null); | ||
273 | 204 | return new Unity.ActivationResponse (Unity.HandledType.HIDE_DASH); | ||
274 | 205 | } | ||
275 | 206 | catch (GLib.Error e) | ||
276 | 207 | { | ||
277 | 208 | warning ("Failed to launch default application for '%s': %s", fakeuri.uri, e.message); | ||
278 | 209 | } | ||
279 | 210 | } | ||
280 | 211 | else | ||
281 | 212 | { | ||
282 | 213 | warning ("Invalid raw uri: '%s'", rawuri); | ||
283 | 214 | } | ||
286 | 215 | return new Unity.ActivationResponse (Unity.HandledType.NOT_HANDLED); | 172 | return new Unity.ActivationResponse (Unity.HandledType.NOT_HANDLED); |
287 | 216 | } | 173 | } |
288 | 217 | 174 | ||
297 | 218 | private Unity.ActivationResponse on_play_video (string rawuri) | 175 | private Unity.Preview? build_preview (ScopeResult result, RemoteVideoDetails? details) |
298 | 219 | { | 176 | { |
299 | 220 | return on_activate_uri (rawuri); | 177 | string title = result.title; |
292 | 221 | } | ||
293 | 222 | |||
294 | 223 | private Unity.Preview? build_preview (RemoteUri uri, RemoteVideoDetails? details) | ||
295 | 224 | { | ||
296 | 225 | string title = uri.title; | ||
300 | 226 | string subtitle = ""; | 178 | string subtitle = ""; |
301 | 227 | string description = ""; | 179 | string description = ""; |
302 | 228 | 180 | ||
303 | @@ -244,11 +196,24 @@ | |||
304 | 244 | } | 196 | } |
305 | 245 | } | 197 | } |
306 | 246 | 198 | ||
308 | 247 | GLib.Icon thumbnail = new GLib.FileIcon (GLib.File.new_for_uri (details != null ? details.image : uri.icon)); | 199 | GLib.Icon thumbnail; |
309 | 200 | if (details != null) | ||
310 | 201 | { | ||
311 | 202 | thumbnail = new GLib.FileIcon (GLib.File.new_for_uri (details.image)); | ||
312 | 203 | } | ||
313 | 204 | else | ||
314 | 205 | { | ||
315 | 206 | try | ||
316 | 207 | { | ||
317 | 208 | thumbnail = GLib.Icon.new_for_string (result.icon_hint); | ||
318 | 209 | } | ||
319 | 210 | catch (Error err) { thumbnail = null; } | ||
320 | 211 | } | ||
321 | 248 | 212 | ||
323 | 249 | var real_preview = new Unity.MoviePreview (title, subtitle, description, thumbnail); | 213 | if (subtitle == "") subtitle = result.comment; |
324 | 214 | var real_preview = new Unity.MoviePreview (title, subtitle, | ||
325 | 215 | description, thumbnail); | ||
326 | 250 | var play_video = new Unity.PreviewAction ("play", _("Play"), null); | 216 | var play_video = new Unity.PreviewAction ("play", _("Play"), null); |
327 | 251 | play_video.activated.connect (on_play_video); | ||
328 | 252 | real_preview.add_action (play_video); | 217 | real_preview.add_action (play_video); |
329 | 253 | 218 | ||
330 | 254 | // For now, rating == -1 and num_ratings == 0 hides the rating widget from the preview | 219 | // For now, rating == -1 and num_ratings == 0 hides the rating widget from the preview |
331 | @@ -277,159 +242,103 @@ | |||
332 | 277 | return real_preview; | 242 | return real_preview; |
333 | 278 | } | 243 | } |
334 | 279 | 244 | ||
336 | 280 | public override async Preview? preview_result (ScopeResult result) | 245 | public async Preview? preview_result (ScopeResult result) |
337 | 281 | { | 246 | { |
340 | 282 | var fakeuri = RemoteUri.from_rawuri (result.uri); | 247 | var uri_variant = result.metadata.lookup (RESULT_DETAILS_URI); |
341 | 283 | if (fakeuri != null) | 248 | var details_uri = uri_variant.get_string (); |
342 | 249 | if (details_uri != null && details_uri != "") | ||
343 | 284 | { | 250 | { |
359 | 285 | RemoteVideoDetails? details = null; | 251 | try |
360 | 286 | 252 | { | |
361 | 287 | if (fakeuri.details_uri != null && fakeuri.details_uri != "") | 253 | var details = yield get_details (details_uri); |
362 | 288 | { | 254 | return build_preview (result, details); |
363 | 289 | try | 255 | } |
364 | 290 | { | 256 | catch (Error e) |
365 | 291 | details = yield get_details (fakeuri.details_uri); | 257 | { |
366 | 292 | } | 258 | warning ("Failed to fetch video details: %s", e.message); |
367 | 293 | catch (Error e) | 259 | } |
353 | 294 | { | ||
354 | 295 | warning ("Failed to fetch video details: %s", e.message); | ||
355 | 296 | } | ||
356 | 297 | } | ||
357 | 298 | |||
358 | 299 | return build_preview (fakeuri, details); | ||
368 | 300 | } | 260 | } |
369 | 301 | else | 261 | else |
370 | 302 | { | 262 | { |
372 | 303 | warning ("Invalid raw uri: '%s'", result.uri); | 263 | warning ("Missing details uri for: '%s'", result.uri); |
373 | 304 | } | 264 | } |
376 | 305 | 265 | return build_preview (result, null); | |
375 | 306 | return null; | ||
377 | 307 | } | 266 | } |
378 | 308 | 267 | ||
379 | 309 | private async RemoteVideoDetails? get_details (string url) throws Error | 268 | private async RemoteVideoDetails? get_details (string url) throws Error |
380 | 310 | { | 269 | { |
397 | 311 | var msg = new Soup.Message ("GET", url); | 270 | try |
398 | 312 | session.queue_message (msg, (session_, msg_) => | 271 | { |
399 | 313 | { | 272 | var msg = yield queue_soup_message (new Soup.Message ("GET", url)); |
384 | 314 | msg = msg_; | ||
385 | 315 | get_details.callback (); | ||
386 | 316 | }); | ||
387 | 317 | |||
388 | 318 | yield; | ||
389 | 319 | |||
390 | 320 | if (msg.status_code != 200) | ||
391 | 321 | { | ||
392 | 322 | warning ("Unable to get details from the server: %u, %s", msg.status_code, msg.reason_phrase); | ||
393 | 323 | return null; | ||
394 | 324 | } | ||
395 | 325 | else | ||
396 | 326 | { | ||
400 | 327 | var details = UbuntuVideoSearch.process_details_results ((string) msg.response_body.data); | 273 | var details = UbuntuVideoSearch.process_details_results ((string) msg.response_body.data); |
401 | 328 | return details; | 274 | return details; |
402 | 329 | } | 275 | } |
470 | 330 | } | 276 | catch (Error err) |
471 | 331 | 277 | { | |
472 | 332 | private async void update_search_async (DeprecatedScopeSearch search, SearchType search_type, GLib.Cancellable? cancellable) | 278 | warning ("Unable to get details from the server: %s", err.message); |
473 | 333 | { | 279 | } |
474 | 334 | var search_string = search.search_string.strip (); | 280 | return null; |
408 | 335 | debug ("Remote search string changed to: %s", search_string); | ||
409 | 336 | |||
410 | 337 | var model = search.results_model; | ||
411 | 338 | model.clear (); | ||
412 | 339 | |||
413 | 340 | // only perform the request if the user has not disabled | ||
414 | 341 | // online/commercial suggestions. That will hide the category as well. | ||
415 | 342 | if (preferences.remote_content_search != Unity.PreferencesManager.RemoteContent.ALL) | ||
416 | 343 | { | ||
417 | 344 | search.finished(); | ||
418 | 345 | return; | ||
419 | 346 | } | ||
420 | 347 | |||
421 | 348 | // create a list of activated sources | ||
422 | 349 | var active_sources = new Gee.ArrayList<string> (null); | ||
423 | 350 | foreach (var opt in sources.options) | ||
424 | 351 | { | ||
425 | 352 | if (source_activated (opt.id)) | ||
426 | 353 | active_sources.add (opt.id); | ||
427 | 354 | } | ||
428 | 355 | |||
429 | 356 | // If all the sources are activated, don't bother passing them as arguments | ||
430 | 357 | if (active_sources.size == sources.options.length ()) | ||
431 | 358 | { | ||
432 | 359 | active_sources.clear (); | ||
433 | 360 | } | ||
434 | 361 | |||
435 | 362 | if (search_type == Unity.SearchType.DEFAULT) | ||
436 | 363 | { | ||
437 | 364 | if (at_least_one_source_is_on (active_sources)) | ||
438 | 365 | { | ||
439 | 366 | try | ||
440 | 367 | { | ||
441 | 368 | yield perform_search (search_string, search, active_sources, cancellable); | ||
442 | 369 | } | ||
443 | 370 | catch (Error e) | ||
444 | 371 | { | ||
445 | 372 | warning ("Search interrupted: %s", e.message); | ||
446 | 373 | } | ||
447 | 374 | } | ||
448 | 375 | } | ||
449 | 376 | |||
450 | 377 | search.finished (); | ||
451 | 378 | } | ||
452 | 379 | |||
453 | 380 | private bool source_activated (string id) | ||
454 | 381 | { | ||
455 | 382 | bool active = sources.get_option (id).active; | ||
456 | 383 | bool filtering = sources.filtering; | ||
457 | 384 | |||
458 | 385 | if ((active && filtering) || (!active && !filtering)) | ||
459 | 386 | return true; | ||
460 | 387 | return false; | ||
461 | 388 | } | ||
462 | 389 | |||
463 | 390 | /* Return a general activation state of all sources of this scope. | ||
464 | 391 | * This is needed, because we don't want to show recommends if an option | ||
465 | 392 | * from another scope is the only one activated | ||
466 | 393 | */ | ||
467 | 394 | private bool at_least_one_source_is_on (Gee.ArrayList<string> active_sources) | ||
468 | 395 | { | ||
469 | 396 | return (sources.filtering && active_sources.size > 0 || !sources.filtering); | ||
475 | 397 | } | 281 | } |
476 | 398 | 282 | ||
477 | 399 | /* Query the server with the search string and the list of sources. | 283 | /* Query the server with the search string and the list of sources. |
478 | 400 | */ | 284 | */ |
480 | 401 | private async void perform_search (string search_string, DeprecatedScopeSearch search, Gee.ArrayList<string> active_sources, GLib.Cancellable? cancellable) throws Error | 285 | private async void perform_search (ScopeSearchBase search) throws Error |
481 | 402 | { | 286 | { |
483 | 403 | search.results_model.clear (); | 287 | if (search.search_context.search_type != Unity.SearchType.DEFAULT) return; |
484 | 288 | var search_string = search.search_context.search_query; | ||
485 | 289 | var result_set = search.search_context.result_set; | ||
486 | 404 | 290 | ||
488 | 405 | if ((search_string == null || search_string == "") && (active_sources.size == 0) && (recommendations.size > 0)) | 291 | if ((search_string == null || search_string == "") && (recommendations.size > 0)) |
489 | 406 | { | 292 | { |
490 | 407 | var time = new DateTime.now_utc (); | 293 | var time = new DateTime.now_utc (); |
491 | 294 | // do we have cached recommendations? | ||
492 | 408 | if (time.to_unix () - recommendations_last_update < REFRESH_INTERVAL) | 295 | if (time.to_unix () - recommendations_last_update < REFRESH_INTERVAL) |
493 | 409 | { | 296 | { |
494 | 410 | debug ("Updating search results with recommendations"); | 297 | debug ("Updating search results with recommendations"); |
496 | 411 | update_results_model (search.results_model, recommendations); | 298 | push_results (result_set, recommendations); |
497 | 299 | result_set.ttl = REFRESH_INTERVAL; | ||
498 | 412 | return; | 300 | return; |
499 | 413 | } | 301 | } |
500 | 414 | } | 302 | } |
501 | 415 | 303 | ||
503 | 416 | var url = UbuntuVideoSearch.build_search_uri (search_string, active_sources); | 304 | var cancellable = search.search_context.cancellable.get_gcancellable (); |
504 | 305 | var url = UbuntuVideoSearch.build_search_uri (search_string, null, search.search_context.search_metadata.form_factor); | ||
505 | 417 | debug ("Querying the server: %s", url); | 306 | debug ("Querying the server: %s", url); |
506 | 418 | 307 | ||
510 | 419 | bool is_treat_yourself = (search_string == null || search_string == "" || active_sources.size == 0); | 308 | bool is_treat_yourself = (search_string == null || search_string == ""); |
511 | 420 | var msg = new Soup.Message ("GET", url); | 309 | |
512 | 421 | 310 | var msg = yield queue_soup_message (new Soup.Message ("GET", url), cancellable); | |
513 | 311 | |||
514 | 312 | var results = UbuntuVideoSearch.process_search_results ((string)msg.response_body.data, is_treat_yourself); | ||
515 | 313 | if (results != null) | ||
516 | 314 | { | ||
517 | 315 | if (search_string == null || search_string.strip () == "") | ||
518 | 316 | { | ||
519 | 317 | debug ("Empty search, updating recommendations"); | ||
520 | 318 | var time = new DateTime.now_utc (); | ||
521 | 319 | recommendations = results; | ||
522 | 320 | recommendations_last_update = time.to_unix (); | ||
523 | 321 | } | ||
524 | 322 | push_results (result_set, results); | ||
525 | 323 | } | ||
526 | 324 | } | ||
527 | 325 | |||
528 | 326 | private async Soup.Message? queue_soup_message (Soup.Message msg, | ||
529 | 327 | GLib.Cancellable? cancellable = null) | ||
530 | 328 | throws Error | ||
531 | 329 | { | ||
532 | 330 | Soup.Message? result_msg = null; | ||
533 | 422 | session.queue_message (msg, (session_, msg_) => | 331 | session.queue_message (msg, (session_, msg_) => |
534 | 423 | { | 332 | { |
537 | 424 | msg = msg_; | 333 | result_msg = msg_; |
538 | 425 | perform_search.callback (); | 334 | queue_soup_message.callback (); |
539 | 426 | }); | 335 | }); |
540 | 427 | 336 | ||
541 | 428 | var cancelled = false; | 337 | var cancelled = false; |
542 | 429 | ulong cancel_id = 0; | 338 | ulong cancel_id = 0; |
543 | 430 | if (cancellable != null) | 339 | if (cancellable != null) |
544 | 431 | { | 340 | { |
546 | 432 | cancel_id = cancellable.connect (() => | 341 | cancel_id = cancellable.cancelled.connect (() => |
547 | 433 | { | 342 | { |
548 | 434 | cancelled = true; | 343 | cancelled = true; |
549 | 435 | session.cancel_message (msg, Soup.KnownStatusCode.CANCELLED); | 344 | session.cancel_message (msg, Soup.KnownStatusCode.CANCELLED); |
550 | @@ -442,39 +351,36 @@ | |||
551 | 442 | { | 351 | { |
552 | 443 | // we can't disconnect right away, as that would deadlock (cause | 352 | // we can't disconnect right away, as that would deadlock (cause |
553 | 444 | // cancel_message doesn't return before invoking the callback) | 353 | // cancel_message doesn't return before invoking the callback) |
555 | 445 | Idle.add (perform_search.callback); | 354 | Idle.add (queue_soup_message.callback); |
556 | 446 | yield; | 355 | yield; |
557 | 447 | cancellable.disconnect (cancel_id); | 356 | cancellable.disconnect (cancel_id); |
558 | 448 | throw new IOError.CANCELLED ("Cancelled"); | 357 | throw new IOError.CANCELLED ("Cancelled"); |
559 | 449 | } | 358 | } |
560 | 450 | 359 | ||
561 | 451 | if (cancellable != null) | 360 | if (cancellable != null) |
562 | 452 | { | ||
563 | 453 | // clean up | ||
564 | 454 | cancellable.disconnect (cancel_id); | 361 | cancellable.disconnect (cancel_id); |
579 | 455 | } | 362 | |
580 | 456 | 363 | if (result_msg.status_code < 100) | |
581 | 457 | var results = handle_search_response (msg, is_treat_yourself); | 364 | { |
582 | 458 | if (results != null) | 365 | throw new IOError.FAILED ("Request failed with error %u", |
583 | 459 | { | 366 | result_msg.status_code); |
584 | 460 | if (search_string == null || search_string.strip () == "" && active_sources.size == 0) | 367 | } |
585 | 461 | { | 368 | |
586 | 462 | debug ("Empty search, updating recommendations"); | 369 | if (result_msg.status_code != 200) |
587 | 463 | var time = new DateTime.now_utc (); | 370 | { |
588 | 464 | recommendations = results; | 371 | throw new IOError.FAILED ("Request returned status code %u", |
589 | 465 | recommendations_last_update = time.to_unix (); | 372 | result_msg.status_code); |
590 | 466 | } | 373 | } |
591 | 467 | update_results_model (search.results_model, results); | 374 | |
592 | 468 | } | 375 | return result_msg; |
593 | 469 | } | 376 | } |
594 | 470 | 377 | ||
596 | 471 | private void update_results_model (Dee.Model model, Gee.ArrayList<RemoteVideoFile?> results) | 378 | private void push_results (Unity.ResultSet result_set, Gee.ArrayList<RemoteVideoFile?> results) |
597 | 472 | { | 379 | { |
598 | 473 | foreach (var video in results) | 380 | foreach (var video in results) |
599 | 474 | { | 381 | { |
600 | 475 | if (video.uri.has_prefix ("http")) | 382 | if (video.uri.has_prefix ("http")) |
601 | 476 | { | 383 | { |
602 | 477 | var fake_uri = new RemoteUri (video.uri, video.title, video.icon, video.details_uri); | ||
603 | 478 | var result_icon = video.icon; | 384 | var result_icon = video.icon; |
604 | 479 | 385 | ||
605 | 480 | if (video.category == CAT_INDEX_MORE && video.price != null && video.price != "") | 386 | if (video.category == CAT_INDEX_MORE && video.price != null && video.price != "") |
606 | @@ -487,9 +393,19 @@ | |||
607 | 487 | 393 | ||
608 | 488 | // aggregator scope remaps categories, so we won't get real category back; | 394 | // aggregator scope remaps categories, so we won't get real category back; |
609 | 489 | // put real category into metadata | 395 | // put real category into metadata |
613 | 490 | var realcat = new Variant.dict_entry (PREVIEW_ON_LMB, new Variant.variant (video.category == CAT_INDEX_MORE)); | 396 | var realcat = new Variant.dict_entry (RESULT_PREVIEW_ON_LMB, |
614 | 491 | var metadata = new Variant.array (VariantType.VARDICT.element (), {realcat}); | 397 | new Variant.variant (video.category == CAT_INDEX_MORE)); |
615 | 492 | model.append (fake_uri.to_rawuri (), result_icon, video.category, ResultType.DEFAULT, "text/html", video.title, video.comment, video.uri, metadata); | 398 | var details_uri = new Variant.dict_entry (RESULT_DETAILS_URI, |
616 | 399 | new Variant.variant (video.details_uri)); | ||
617 | 400 | var metadata = new Variant.array (VariantType.VARDICT.element (), {realcat, details_uri}); | ||
618 | 401 | |||
619 | 402 | var result = new Variant ("(ssuussss@a{sv})", video.uri, | ||
620 | 403 | result_icon, video.category, | ||
621 | 404 | ResultType.DEFAULT, "text/html", | ||
622 | 405 | video.title, video.comment, | ||
623 | 406 | video.uri, metadata); | ||
624 | 407 | |||
625 | 408 | result_set.add_result_from_variant (result); | ||
626 | 493 | } | 409 | } |
627 | 494 | } | 410 | } |
628 | 495 | } | 411 | } |
629 | @@ -501,18 +417,20 @@ | |||
630 | 501 | var ev = new Zeitgeist.Event.full (Zeitgeist.ZG_ACCESS_EVENT, Zeitgeist.ZG_USER_ACTIVITY, "lens://unity-lens-video"); | 417 | var ev = new Zeitgeist.Event.full (Zeitgeist.ZG_ACCESS_EVENT, Zeitgeist.ZG_USER_ACTIVITY, "lens://unity-lens-video"); |
631 | 502 | templates.add ((ev as GLib.Object).ref()); | 418 | templates.add ((ev as GLib.Object).ref()); |
632 | 503 | var data_source = new Zeitgeist.DataSource.full ("98898", "Unity Video Lens", "", templates); | 419 | var data_source = new Zeitgeist.DataSource.full ("98898", "Unity Video Lens", "", templates); |
634 | 504 | zg_sources.register_data_source (data_source, null); | 420 | zg_sources.register_data_source.begin (data_source, null); |
635 | 505 | } | 421 | } |
636 | 506 | 422 | ||
637 | 507 | private void zeitgeist_insert_event (string uri, string title, string icon) | 423 | private void zeitgeist_insert_event (string uri, string title, string icon) |
638 | 508 | { | 424 | { |
639 | 425 | if (!use_zeitgeist) return; | ||
640 | 426 | |||
641 | 509 | var subject = new Zeitgeist.Subject.full (uri, Zeitgeist.NFO_VIDEO, Zeitgeist.NFO_REMOTE_DATA_OBJECT, "", uri, title, icon); | 427 | var subject = new Zeitgeist.Subject.full (uri, Zeitgeist.NFO_VIDEO, Zeitgeist.NFO_REMOTE_DATA_OBJECT, "", uri, title, icon); |
642 | 510 | var event = new Zeitgeist.Event.full (Zeitgeist.ZG_ACCESS_EVENT, Zeitgeist.ZG_USER_ACTIVITY, "lens://unity-lens-video"); | 428 | var event = new Zeitgeist.Event.full (Zeitgeist.ZG_ACCESS_EVENT, Zeitgeist.ZG_USER_ACTIVITY, "lens://unity-lens-video"); |
643 | 511 | event.add_subject (subject); | 429 | event.add_subject (subject); |
644 | 512 | 430 | ||
645 | 513 | var ev_array = new PtrArray.sized(1); | 431 | var ev_array = new PtrArray.sized(1); |
646 | 514 | ev_array.add ((event as GLib.Object).ref ()); | 432 | ev_array.add ((event as GLib.Object).ref ()); |
648 | 515 | Zeitgeist.Log.get_default ().insert_events_from_ptrarray (ev_array, null); | 433 | Zeitgeist.Log.get_default ().insert_events_from_ptrarray.begin (ev_array, null); |
649 | 516 | } | 434 | } |
650 | 517 | } | 435 | } |
651 | 518 | } | 436 | } |
652 | 519 | 437 | ||
653 | === removed file 'src/remote-uri.vala' | |||
654 | --- src/remote-uri.vala 2012-11-15 13:34:30 +0000 | |||
655 | +++ src/remote-uri.vala 1970-01-01 00:00:00 +0000 | |||
656 | @@ -1,52 +0,0 @@ | |||
657 | 1 | /* | ||
658 | 2 | * Copyright (C) 2012 Canonical Ltd | ||
659 | 3 | * | ||
660 | 4 | * This program is free software: you can redistribute it and/or modify | ||
661 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
662 | 6 | * published by the Free Software Foundation. | ||
663 | 7 | * | ||
664 | 8 | * This program is distributed in the hope that it will be useful, | ||
665 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
666 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
667 | 11 | * GNU General Public License for more details. | ||
668 | 12 | * | ||
669 | 13 | * You should have received a copy of the GNU General Public License | ||
670 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
671 | 15 | * | ||
672 | 16 | * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> | ||
673 | 17 | */ | ||
674 | 18 | |||
675 | 19 | namespace Unity.VideoLens | ||
676 | 20 | { | ||
677 | 21 | public class RemoteUri | ||
678 | 22 | { | ||
679 | 23 | public string uri { get; set; } | ||
680 | 24 | public string title { get; set; } | ||
681 | 25 | public string icon { get; set; } | ||
682 | 26 | public string details_uri { get; set; } | ||
683 | 27 | |||
684 | 28 | public RemoteUri (string uri, string title, string icon, string details_uri) | ||
685 | 29 | { | ||
686 | 30 | this.uri = uri; | ||
687 | 31 | this.title = title; | ||
688 | 32 | this.icon = icon; | ||
689 | 33 | this.details_uri = details_uri; | ||
690 | 34 | } | ||
691 | 35 | |||
692 | 36 | public static RemoteUri? from_rawuri (string raw_uri) | ||
693 | 37 | { | ||
694 | 38 | RemoteUri uri = null; | ||
695 | 39 | string[] args = raw_uri.split ("lens-meta://", 4); | ||
696 | 40 | if (args.length == 4) | ||
697 | 41 | { | ||
698 | 42 | uri = new RemoteUri (args[0], args[1], args[2], args[3]); | ||
699 | 43 | } | ||
700 | 44 | return uri; | ||
701 | 45 | } | ||
702 | 46 | |||
703 | 47 | public string to_rawuri () | ||
704 | 48 | { | ||
705 | 49 | return string.join ("lens-meta://", uri, title, icon, details_uri); | ||
706 | 50 | } | ||
707 | 51 | } | ||
708 | 52 | } | ||
709 | 53 | \ No newline at end of file | 0 | \ No newline at end of file |
710 | 54 | 1 | ||
711 | === modified file 'src/remote-video-main.vala' | |||
712 | --- src/remote-video-main.vala 2013-05-16 11:31:51 +0000 | |||
713 | +++ src/remote-video-main.vala 2013-09-17 12:19:35 +0000 | |||
714 | @@ -19,10 +19,6 @@ | |||
715 | 19 | 19 | ||
716 | 20 | namespace Unity.VideoLens { | 20 | namespace Unity.VideoLens { |
717 | 21 | 21 | ||
718 | 22 | static const string BUS_NAME = "net.launchpad.scope.RemoteVideos"; | ||
719 | 23 | Unity.DeprecatedScope scope; | ||
720 | 24 | static Application? app = null; | ||
721 | 25 | |||
722 | 26 | public static int main (string[] args) | 22 | public static int main (string[] args) |
723 | 27 | { | 23 | { |
724 | 28 | GLib.Environment.set_prgname ("unity-remote-video-scope"); | 24 | GLib.Environment.set_prgname ("unity-remote-video-scope"); |
725 | @@ -34,28 +30,19 @@ | |||
726 | 34 | GLib.Intl.bind_textdomain_codeset (Config.PACKAGE, "UTF-8"); | 30 | GLib.Intl.bind_textdomain_codeset (Config.PACKAGE, "UTF-8"); |
727 | 35 | GLib.Intl.setlocale(GLib.LocaleCategory.ALL, ""); | 31 | GLib.Intl.setlocale(GLib.LocaleCategory.ALL, ""); |
728 | 36 | 32 | ||
729 | 33 | var scope = new RemoteVideoScope (); | ||
730 | 34 | var exporter = new Unity.ScopeDBusConnector (scope); | ||
731 | 37 | try | 35 | try |
732 | 38 | { | 36 | { |
753 | 39 | app = Extras.dbus_own_name (BUS_NAME, () => | 37 | exporter.export (); |
754 | 40 | { | 38 | } |
755 | 41 | scope = new RemoteVideoScope (); | 39 | catch (GLib.Error e) |
756 | 42 | scope.export (); | 40 | { |
757 | 43 | }); | 41 | error ("Cannot export scope to DBus: %s", e.message); |
758 | 44 | } | 42 | } |
759 | 45 | catch (Error e) | 43 | Unity.ScopeDBusConnector.run (); |
760 | 46 | { | 44 | |
761 | 47 | warning ("Failed to start video lens daemon: %s\n", e.message); | 45 | return 0; |
742 | 48 | return 1; | ||
743 | 49 | } | ||
744 | 50 | |||
745 | 51 | if (app == null) | ||
746 | 52 | { | ||
747 | 53 | warning ("Another instance of the Unity Videos Lens " + | ||
748 | 54 | "already appears to be running.\nBailing out.\n"); | ||
749 | 55 | return 2; | ||
750 | 56 | } | ||
751 | 57 | |||
752 | 58 | return app.run (); | ||
762 | 59 | } | 46 | } |
763 | 60 | 47 | ||
764 | 61 | } /* namespace */ | 48 | } /* namespace */ |
765 | 62 | 49 | ||
766 | === modified file 'src/ubuntu-video-search.vala' | |||
767 | --- src/ubuntu-video-search.vala 2012-11-27 12:07:22 +0000 | |||
768 | +++ src/ubuntu-video-search.vala 2013-09-17 12:19:35 +0000 | |||
769 | @@ -28,10 +28,10 @@ | |||
770 | 28 | 28 | ||
771 | 29 | public static string recommendations_uri () | 29 | public static string recommendations_uri () |
772 | 30 | { | 30 | { |
774 | 31 | return SERVER + "/search?q=&sources=Amazon"; | 31 | return SERVER + "/search?q="; |
775 | 32 | } | 32 | } |
776 | 33 | 33 | ||
778 | 34 | public static string build_search_uri (string query, Gee.ArrayList<string>? sources) | 34 | public static string build_search_uri (string query, Gee.ArrayList<string>? sources, string? form_factor = null) |
779 | 35 | { | 35 | { |
780 | 36 | var uri = new StringBuilder (); | 36 | var uri = new StringBuilder (); |
781 | 37 | uri.append (SERVER); | 37 | uri.append (SERVER); |
782 | @@ -48,6 +48,11 @@ | |||
783 | 48 | uri.append (sources[i]); | 48 | uri.append (sources[i]); |
784 | 49 | } | 49 | } |
785 | 50 | } | 50 | } |
786 | 51 | if (form_factor != null) | ||
787 | 52 | { | ||
788 | 53 | uri.append ("&form_factor="); | ||
789 | 54 | uri.append (form_factor); | ||
790 | 55 | } | ||
791 | 51 | return uri.str; | 56 | return uri.str; |
792 | 52 | } | 57 | } |
793 | 53 | 58 | ||
794 | @@ -226,4 +231,4 @@ | |||
795 | 226 | }); | 231 | }); |
796 | 227 | return videos; | 232 | return videos; |
797 | 228 | } | 233 | } |
798 | 229 | } | ||
799 | 230 | \ No newline at end of file | 234 | \ No newline at end of file |
800 | 235 | } | ||
801 | 231 | 236 | ||
802 | === modified file 'tests/unit/Makefile.am' | |||
803 | --- tests/unit/Makefile.am 2013-06-20 18:12:31 +0000 | |||
804 | +++ tests/unit/Makefile.am 2013-09-17 12:19:35 +0000 | |||
805 | @@ -65,7 +65,6 @@ | |||
806 | 65 | $(top_srcdir)/src/ubuntu-video-search.vala \ | 65 | $(top_srcdir)/src/ubuntu-video-search.vala \ |
807 | 66 | $(top_srcdir)/src/video-file.vala \ | 66 | $(top_srcdir)/src/video-file.vala \ |
808 | 67 | $(top_srcdir)/src/remote-scope.vala \ | 67 | $(top_srcdir)/src/remote-scope.vala \ |
809 | 68 | $(top_srcdir)/src/remote-uri.vala \ | ||
810 | 69 | $(top_srcdir)/src/utils.vala \ | 68 | $(top_srcdir)/src/utils.vala \ |
811 | 70 | $(NULL) | 69 | $(NULL) |
812 | 71 | 70 |
PASSED: Continuous integration, rev:124 jenkins. qa.ubuntu. com/job/ unity-lens- video-ci/ 9/ jenkins. qa.ubuntu. com/job/ unity-lens- video-saucy- amd64-ci/ 4 jenkins. qa.ubuntu. com/job/ unity-lens- video-saucy- armhf-ci/ 4 jenkins. qa.ubuntu. com/job/ unity-lens- video-saucy- i386-ci/ 4
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-lens- video-ci/ 9/rebuild
http://