Merge lp:~gary-wzl77/unity-scope-soundcloud/unity-scope-soundcloud into lp:unity-scope-soundcloud
- unity-scope-soundcloud
- Merge into trunk
Proposed by
Gary.Wang
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 40 | ||||
Proposed branch: | lp:~gary-wzl77/unity-scope-soundcloud/unity-scope-soundcloud | ||||
Merge into: | lp:unity-scope-soundcloud | ||||
Diff against target: |
2654 lines (+1539/-260) 26 files modified
CMakeLists.txt (+1/-1) click/manifest.json.in (+1/-1) click/soundcloud.apparmor (+1/-1) click/soundcloud.provider.in (+1/-0) data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in (+2/-0) include/api/client.h (+28/-0) include/api/comment.h (+70/-0) include/api/resource.h (+2/-1) include/api/track.h (+21/-0) include/api/user.h (+20/-0) include/scope/activation.h (+64/-0) include/scope/preview.h (+9/-1) include/scope/query.h (+6/-0) include/scope/scope.h (+9/-0) po/POTFILES.in (+16/-12) po/en_GB.po (+147/-63) po/unity-scope-soundcloud.pot (+149/-73) src/CMakeLists.txt (+2/-0) src/api/client.cpp (+323/-9) src/api/comment.cpp (+71/-0) src/api/track.cpp (+39/-1) src/api/user.cpp (+30/-0) src/scope/activation.cpp (+91/-0) src/scope/preview.cpp (+245/-73) src/scope/query.cpp (+181/-23) src/scope/scope.cpp (+10/-1) |
||||
To merge this branch: | bzr merge lp:~gary-wzl77/unity-scope-soundcloud/unity-scope-soundcloud | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity API Team | Pending | ||
Review via email: mp+283759@code.launchpad.net |
Commit message
Add new features offered by soundcloud which are missing in this scope.
Description of the change
Add new features offered by soundcloud which are missing in this scope.
1.Add detailed track info in card view
2.Load high resolution track picture
3.Support to retrieve comment list
4.Support to post a comment
5.Waveform image url fixed when loading auth user favorite streams
6.Support to mark a "like" for tracks
7.Support to follow an artist
8.Bump framework to ubuntu-sdk-15.04
9.Fix login failed
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-12-04 15:01:39 +0000 |
3 | +++ CMakeLists.txt 2016-02-02 11:41:52 +0000 |
4 | @@ -55,7 +55,7 @@ |
5 | set(UBUNTU_PROJECT_TYPE "Scope" CACHE INTERNAL "Tells QtCreator this is a Scope project") |
6 | |
7 | # Important project paths |
8 | -set(SCOPE_VERSION "1.0.1-${BZR_REVNO}") |
9 | +set(SCOPE_VERSION "1.6.0-${BZR_REVNO}") |
10 | set(CMAKE_INSTALL_PREFIX /) |
11 | set(SCOPE_INSTALL_DIR "/soundcloud") |
12 | set(GETTEXT_PACKAGE "unity-scope-soundcloud") |
13 | |
14 | === modified file 'click/manifest.json.in' |
15 | --- click/manifest.json.in 2014-11-12 13:18:58 +0000 |
16 | +++ click/manifest.json.in 2016-02-02 11:41:52 +0000 |
17 | @@ -1,7 +1,7 @@ |
18 | { |
19 | "architecture": "@CLICK_ARCH@", |
20 | "description": "Listen to your favourite tracks on SoundCloud", |
21 | - "framework": "ubuntu-sdk-14.10-dev2", |
22 | + "framework": "ubuntu-sdk-15.04", |
23 | "hooks": { |
24 | "soundcloud": { |
25 | "apparmor": "soundcloud.apparmor", |
26 | |
27 | === modified file 'click/soundcloud.apparmor' |
28 | --- click/soundcloud.apparmor 2014-11-11 06:54:01 +0000 |
29 | +++ click/soundcloud.apparmor 2016-02-02 11:41:52 +0000 |
30 | @@ -3,7 +3,7 @@ |
31 | "policy_groups": [ |
32 | "accounts" |
33 | ], |
34 | - "policy_version": 1.2 |
35 | + "policy_version": 1.3 |
36 | } |
37 | |
38 | |
39 | |
40 | === modified file 'click/soundcloud.provider.in' |
41 | --- click/soundcloud.provider.in 2014-11-17 09:44:59 +0000 |
42 | +++ click/soundcloud.provider.in 2016-02-02 11:41:52 +0000 |
43 | @@ -21,6 +21,7 @@ |
44 | <setting type="as" name="Scope">['non-expiring']</setting> |
45 | <setting name="ClientId">eadbbc8380aa72be1412e2abe5f8e4ca</setting> |
46 | <setting type="as" name="AllowedSchemes">['https','http']</setting> |
47 | + <setting name="DisableStateParameter" type="b">true</setting> |
48 | </group> |
49 | </group> |
50 | </group> |
51 | |
52 | === modified file 'data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in' |
53 | --- data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in 2014-11-18 15:08:53 +0000 |
54 | +++ data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in 2016-02-02 11:41:52 +0000 |
55 | @@ -13,3 +13,5 @@ |
56 | PageHeader.ForegroundColor = #ffffffff |
57 | PageHeader.Logo = logo.png |
58 | PageHeader.NavigationBackground = color:///#ddffffff |
59 | +PreviewButtonColor=#FF5500 |
60 | + |
61 | |
62 | === modified file 'include/api/client.h' |
63 | --- include/api/client.h 2014-12-04 13:39:07 +0000 |
64 | +++ include/api/client.h 2016-02-02 11:41:52 +0000 |
65 | @@ -14,6 +14,7 @@ |
66 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
67 | * |
68 | * Author: Pete Woods <pete.woods@canonical.com> |
69 | + * Gary Wang <gary.wang@canonical.com> |
70 | */ |
71 | |
72 | #ifndef API_CLIENT_H_ |
73 | @@ -21,6 +22,7 @@ |
74 | |
75 | #include <api/config.h> |
76 | #include <api/track.h> |
77 | +#include <api/comment.h> |
78 | |
79 | #include <unity/scopes/OnlineAccountClient.h> |
80 | |
81 | @@ -62,6 +64,32 @@ |
82 | |
83 | virtual std::future<std::deque<Track>> stream_tracks(int limit=0); |
84 | |
85 | + virtual std::future<std::deque<Comment>> track_comments(const std::string &trackid); |
86 | + |
87 | + virtual std::future<bool> post_comment(const std::string &trackid, |
88 | + const std::string &postmsg); |
89 | + |
90 | + virtual std::future<std::deque<Track>> favorite_tracks(); |
91 | + |
92 | + virtual std::future<std::deque<Track>> get_user_tracks(const std::string &userid, |
93 | + int limit = 0); |
94 | + |
95 | + virtual std::future<bool> is_fav_track(const std::string &trackid); |
96 | + |
97 | + virtual std::future<bool> like_track(const std::string &trackid); |
98 | + |
99 | + virtual std::future<bool> delete_like_track(const std::string &trackid); |
100 | + |
101 | + virtual std::future<bool> is_user_follower(const std::string &userid); |
102 | + |
103 | + virtual std::future<bool> follow_user(const std::string &userid); |
104 | + |
105 | + virtual std::future<bool> unfollow_user(const std::string &userid); |
106 | + |
107 | + virtual std::future<User> get_authuser_info(); |
108 | + |
109 | + virtual std::future<User> get_user_info(const std::string &userid); |
110 | + |
111 | /** |
112 | * Cancel any pending queries (this method can be called from a different thread) |
113 | */ |
114 | |
115 | === added file 'include/api/comment.h' |
116 | --- include/api/comment.h 1970-01-01 00:00:00 +0000 |
117 | +++ include/api/comment.h 2016-02-02 11:41:52 +0000 |
118 | @@ -0,0 +1,70 @@ |
119 | +/* |
120 | + * Copyright (C) 2014 Canonical, Ltd. |
121 | + * |
122 | + * This library is free software; you can redistribute it and/or modify it under |
123 | + * the terms of version 3 of the GNU Lesser General Public License as published |
124 | + * by the Free Software Foundation. |
125 | + * |
126 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
127 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
128 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
129 | + * details. |
130 | + * |
131 | + * You should have received a copy of the GNU Lesser General Public License |
132 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
133 | + * |
134 | + * Author: Pete Woods <pete.woods@canonical.com> |
135 | + * Gary Wang <gary.wang@canonical.com> |
136 | + */ |
137 | + |
138 | +#ifndef API_COMMENT_H_ |
139 | +#define API_COMMENT_H_ |
140 | + |
141 | +#include <api/user.h> |
142 | + |
143 | +#include <memory> |
144 | +#include <string> |
145 | + |
146 | +namespace Json { |
147 | +class Value; |
148 | +} |
149 | + |
150 | +namespace api { |
151 | + |
152 | +class Comment: public Resource { |
153 | +public: |
154 | + typedef std::shared_ptr<Comment> Ptr; |
155 | + |
156 | + Comment(const Json::Value &data); |
157 | + |
158 | + virtual ~Comment() = default; |
159 | + |
160 | + const unsigned int & id() const override; |
161 | + |
162 | + const std::string & title() const override; |
163 | + |
164 | + const std::string & artwork() const override; |
165 | + |
166 | + const std::string & body() const; |
167 | + |
168 | + const std::string & created_at() const; |
169 | + |
170 | + const User & user() const; |
171 | + |
172 | + Kind kind() const override; |
173 | + |
174 | + std::string kind_str() const override; |
175 | + |
176 | +protected: |
177 | + std::string body_; |
178 | + |
179 | + std::string created_at_; |
180 | + |
181 | + unsigned int id_; |
182 | + |
183 | + User user_; |
184 | +}; |
185 | + |
186 | +} |
187 | + |
188 | +#endif // API_COMMENT_H_ |
189 | |
190 | === modified file 'include/api/resource.h' |
191 | --- include/api/resource.h 2014-11-05 16:17:51 +0000 |
192 | +++ include/api/resource.h 2016-02-02 11:41:52 +0000 |
193 | @@ -14,6 +14,7 @@ |
194 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
195 | * |
196 | * Author: Pete Woods <pete.woods@canonical.com> |
197 | + * Gary Wang <gary.wang@canonical.com> |
198 | */ |
199 | |
200 | #ifndef API_RESOURCE_H_ |
201 | @@ -27,7 +28,7 @@ |
202 | class Resource { |
203 | public: |
204 | enum class Kind { |
205 | - track, user |
206 | + track, user, comment, |
207 | }; |
208 | |
209 | typedef std::shared_ptr<Resource> Ptr; |
210 | |
211 | === modified file 'include/api/track.h' |
212 | --- include/api/track.h 2014-11-06 11:40:45 +0000 |
213 | +++ include/api/track.h 2016-02-02 11:41:52 +0000 |
214 | @@ -14,6 +14,7 @@ |
215 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
216 | * |
217 | * Author: Pete Woods <pete.woods@canonical.com> |
218 | + * Gary Wang <gary.wang@canonical.com> |
219 | */ |
220 | |
221 | #ifndef API_TRACK_H_ |
222 | @@ -76,6 +77,16 @@ |
223 | |
224 | unsigned int favoritings_count() const; |
225 | |
226 | + unsigned int comment_count() const; |
227 | + |
228 | + unsigned int repost_count() const; |
229 | + |
230 | + unsigned int likes_count() const; |
231 | + |
232 | + const std::string & genre() const; |
233 | + |
234 | + const std::string & original_format() const; |
235 | + |
236 | const User & user() const; |
237 | |
238 | Kind kind() const override; |
239 | @@ -121,6 +132,16 @@ |
240 | |
241 | unsigned int favoritings_count_; |
242 | |
243 | + unsigned int comment_count_; |
244 | + |
245 | + unsigned int repost_count_; |
246 | + |
247 | + unsigned int likes_count_; |
248 | + |
249 | + std::string genre_; |
250 | + |
251 | + std::string original_format_; |
252 | + |
253 | User user_; |
254 | }; |
255 | |
256 | |
257 | === modified file 'include/api/user.h' |
258 | --- include/api/user.h 2014-11-05 16:17:51 +0000 |
259 | +++ include/api/user.h 2016-02-02 11:41:52 +0000 |
260 | @@ -44,6 +44,16 @@ |
261 | |
262 | const unsigned int & id() const override; |
263 | |
264 | + const std::string & permalink_url() const; |
265 | + |
266 | + const unsigned int & track_count() const; |
267 | + |
268 | + const unsigned int & followers_count() const; |
269 | + |
270 | + const unsigned int & followings_count() const; |
271 | + |
272 | + const std::string & bio() const; |
273 | + |
274 | Kind kind() const override; |
275 | |
276 | std::string kind_str() const override; |
277 | @@ -54,6 +64,16 @@ |
278 | unsigned int id_; |
279 | |
280 | std::string artwork_; |
281 | + |
282 | + std::string permalink_; |
283 | + |
284 | + unsigned int track_count_; |
285 | + |
286 | + unsigned int followers_count_; |
287 | + |
288 | + unsigned int followings_count_; |
289 | + |
290 | + std::string bio_; |
291 | }; |
292 | |
293 | } |
294 | |
295 | === added file 'include/scope/activation.h' |
296 | --- include/scope/activation.h 1970-01-01 00:00:00 +0000 |
297 | +++ include/scope/activation.h 2016-02-02 11:41:52 +0000 |
298 | @@ -0,0 +1,64 @@ |
299 | +/* |
300 | + * Copyright (C) 2014 Canonical, Ltd. |
301 | + * |
302 | + * This library is free software; you can redistribute it and/or modify it under |
303 | + * the terms of version 3 of the GNU Lesser General Public License as published |
304 | + * by the Free Software Foundation. |
305 | + * |
306 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
307 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
308 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
309 | + * details. |
310 | + * |
311 | + * You should have received a copy of the GNU Lesser General Public License |
312 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
313 | + * |
314 | + * Author: Pete Woods <pete.woods@canonical.com> |
315 | + * Gary Wang <gary.wang@canonical.com> |
316 | + */ |
317 | + |
318 | +#ifndef SCOPE_ACTIVATIOIN_H_ |
319 | +#define SCOPE_ACTIVATIOIN_H_ |
320 | + |
321 | +#include <api/client.h> |
322 | + |
323 | +#include <unity/scopes/ActivationQueryBase.h> |
324 | + |
325 | +namespace unity { |
326 | +namespace scopes { |
327 | +class Result; |
328 | +} |
329 | +} |
330 | + |
331 | +namespace scope { |
332 | + |
333 | +/** |
334 | + * Represents an individual action request. |
335 | + * |
336 | + * Each time a action is performed in the UI a new Action |
337 | + * object is created. |
338 | + */ |
339 | +class Activation : public unity::scopes::ActivationQueryBase |
340 | +{ |
341 | +public: |
342 | + Activation(const unity::scopes::Result &result, |
343 | + const unity::scopes::ActionMetadata & metadata, |
344 | + std::string const& action_id, |
345 | + std::shared_ptr<unity::scopes::OnlineAccountClient> oa_client); |
346 | + |
347 | + ~Activation() = default; |
348 | + |
349 | + /** |
350 | + * Trigger the action object with action id. |
351 | + */ |
352 | + virtual unity::scopes::ActivationResponse activate() override; |
353 | + |
354 | +private: |
355 | + std::string const action_id_; |
356 | + |
357 | + api::Client client_; |
358 | +}; |
359 | + |
360 | +} |
361 | + |
362 | +#endif // SCOPE_ACTIVATION_H_ |
363 | |
364 | === modified file 'include/scope/preview.h' |
365 | --- include/scope/preview.h 2014-11-10 11:54:32 +0000 |
366 | +++ include/scope/preview.h 2016-02-02 11:41:52 +0000 |
367 | @@ -14,12 +14,16 @@ |
368 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
369 | * |
370 | * Author: Pete Woods <pete.woods@canonical.com> |
371 | + * Gary Wang <gary.wang@canonical.com> |
372 | */ |
373 | |
374 | #ifndef SCOPE_PREVIEW_H_ |
375 | #define SCOPE_PREVIEW_H_ |
376 | |
377 | +#include <api/client.h> |
378 | + |
379 | #include <unity/scopes/PreviewQueryBase.h> |
380 | +#include <unity/scopes/OnlineAccountClient.h> |
381 | |
382 | namespace unity { |
383 | namespace scopes { |
384 | @@ -38,7 +42,8 @@ |
385 | class Preview: public unity::scopes::PreviewQueryBase { |
386 | public: |
387 | Preview(const unity::scopes::Result &result, |
388 | - const unity::scopes::ActionMetadata &metadata); |
389 | + const unity::scopes::ActionMetadata &metadata, |
390 | + std::shared_ptr<unity::scopes::OnlineAccountClient> oa_client); |
391 | |
392 | ~Preview() = default; |
393 | |
394 | @@ -48,6 +53,9 @@ |
395 | * Populates the reply object with preview information. |
396 | */ |
397 | void run(unity::scopes::PreviewReplyProxy const& reply) override; |
398 | + |
399 | +private: |
400 | + api::Client client_; |
401 | }; |
402 | |
403 | } |
404 | |
405 | === modified file 'include/scope/query.h' |
406 | --- include/scope/query.h 2014-12-04 13:22:43 +0000 |
407 | +++ include/scope/query.h 2016-02-02 11:41:52 +0000 |
408 | @@ -51,6 +51,12 @@ |
409 | const unity::scopes::Category::SCPtr &category, |
410 | const api::Track &track); |
411 | |
412 | + bool push_user_info(const unity::scopes::SearchReplyProxy &reply, |
413 | + const unity::scopes::Category::SCPtr &category, |
414 | + const api::User &user); |
415 | + |
416 | + bool show_empty_tip(const unity::scopes::SearchReplyProxy &reply); |
417 | + |
418 | api::Client client_; |
419 | }; |
420 | |
421 | |
422 | === modified file 'include/scope/scope.h' |
423 | --- include/scope/scope.h 2014-12-04 13:24:10 +0000 |
424 | +++ include/scope/scope.h 2016-02-02 11:41:52 +0000 |
425 | @@ -61,6 +61,15 @@ |
426 | unity::scopes::CannedQuery const& q, |
427 | unity::scopes::SearchMetadata const&) override; |
428 | |
429 | + /** |
430 | + * Called each time a new action is requested |
431 | + */ |
432 | + unity::scopes::ActivationQueryBase::UPtr perform_action( |
433 | + const unity::scopes::Result &result, |
434 | + const unity::scopes::ActionMetadata &metadata, |
435 | + std::string const& widget_id, |
436 | + std::string const& action_id) override; |
437 | + |
438 | protected: |
439 | std::shared_ptr<unity::scopes::OnlineAccountClient> oa_client_; |
440 | }; |
441 | |
442 | === modified file 'po/POTFILES.in' |
443 | --- po/POTFILES.in 2014-11-18 15:08:53 +0000 |
444 | +++ po/POTFILES.in 2016-02-02 11:41:52 +0000 |
445 | @@ -1,16 +1,20 @@ |
446 | -[type: gettext/ini] data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in |
447 | -include/api/resource.h |
448 | -include/api/user.h |
449 | -include/api/config.h |
450 | -include/api/track.h |
451 | -include/api/client.h |
452 | +tests/unit/scope/test-scope.cpp |
453 | +src/scope/preview.cpp |
454 | +src/scope/activation.cpp |
455 | +src/scope/scope.cpp |
456 | +src/scope/query.cpp |
457 | +src/api/user.cpp |
458 | +src/api/client.cpp |
459 | +src/api/track.cpp |
460 | +src/api/comment.cpp |
461 | include/scope/preview.h |
462 | include/scope/localization.h |
463 | +include/scope/activation.h |
464 | include/scope/query.h |
465 | include/scope/scope.h |
466 | -src/api/client.cpp |
467 | -src/api/track.cpp |
468 | -src/api/user.cpp |
469 | -src/scope/query.cpp |
470 | -src/scope/scope.cpp |
471 | -src/scope/preview.cpp |
472 | \ No newline at end of file |
473 | +include/api/resource.h |
474 | +include/api/track.h |
475 | +include/api/comment.h |
476 | +include/api/client.h |
477 | +include/api/config.h |
478 | +include/api/user.h |
479 | |
480 | === modified file 'po/en_GB.po' |
481 | --- po/en_GB.po 2014-11-18 16:42:10 +0000 |
482 | +++ po/en_GB.po 2016-02-02 11:41:52 +0000 |
483 | @@ -8,7 +8,7 @@ |
484 | msgstr "" |
485 | "Project-Id-Version: unity-scope-soundcloud\n" |
486 | "Report-Msgid-Bugs-To: \n" |
487 | -"POT-Creation-Date: 2014-11-18 14:00+0000\n" |
488 | +"POT-Creation-Date: 2016-01-26 16:58+0800\n" |
489 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
490 | "Last-Translator: Pete Woods <EMAIL@ADDRESS>\n" |
491 | "Language-Team: LANGUAGE <LL@li.org>\n" |
492 | @@ -17,226 +17,310 @@ |
493 | "Content-Type: text/plain; charset=UTF-8\n" |
494 | "Content-Transfer-Encoding: 8bit\n" |
495 | |
496 | -#: ../src/scope/query.cpp:112 |
497 | +#: ../src/scope/query.cpp:416 |
498 | +msgid "</b> followers" |
499 | +msgstr "" |
500 | + |
501 | +#: ../src/scope/query.cpp:417 |
502 | +msgid "</b> followings" |
503 | +msgstr "" |
504 | + |
505 | +#: ../src/scope/query.cpp:415 |
506 | +msgid "</b> tracks" |
507 | +msgstr "" |
508 | + |
509 | +#: ../src/scope/query.cpp:148 |
510 | msgid "Alternative Rock" |
511 | msgstr "Alternative Rock" |
512 | |
513 | -#: ../src/scope/query.cpp:112 |
514 | +#: ../src/scope/query.cpp:148 |
515 | msgid "Ambient" |
516 | msgstr "Ambient" |
517 | |
518 | -#: ../src/scope/query.cpp:97 |
519 | +#: ../src/scope/query.cpp:133 |
520 | msgid "Audiobooks" |
521 | msgstr "Audiobooks" |
522 | |
523 | -#: ../src/scope/query.cpp:98 |
524 | +#: ../src/scope/query.cpp:134 |
525 | msgid "Business" |
526 | msgstr "Business" |
527 | |
528 | -#: ../src/scope/preview.cpp:84 |
529 | +#: ../src/scope/preview.cpp:198 |
530 | msgid "Buy" |
531 | msgstr "Buy" |
532 | |
533 | -#: ../src/scope/query.cpp:112 |
534 | +#: ../src/scope/query.cpp:148 |
535 | msgid "Classical" |
536 | msgstr "Classical" |
537 | |
538 | -#: ../src/scope/query.cpp:98 |
539 | +#: ../src/scope/query.cpp:134 |
540 | msgid "Comedy" |
541 | msgstr "Comedy" |
542 | |
543 | -#: ../src/scope/query.cpp:112 |
544 | +#: ../src/scope/query.cpp:148 |
545 | msgid "Country" |
546 | msgstr "Country" |
547 | |
548 | -#: ../src/scope/query.cpp:113 |
549 | +#: ../src/scope/query.cpp:149 |
550 | msgid "Dance" |
551 | msgstr "Dance" |
552 | |
553 | -#: ../src/scope/query.cpp:113 |
554 | +#: ../src/scope/query.cpp:149 |
555 | msgid "Deep House" |
556 | msgstr "Deep House" |
557 | |
558 | -#: ../src/scope/query.cpp:113 |
559 | +#: ../src/scope/query.cpp:149 |
560 | msgid "Disco" |
561 | msgstr "Disco" |
562 | |
563 | -#: ../src/scope/query.cpp:113 |
564 | +#: ../src/scope/query.cpp:149 |
565 | msgid "Drum & Bass" |
566 | msgstr "Drum & Bass" |
567 | |
568 | -#: ../src/scope/query.cpp:113 |
569 | +#: ../src/scope/query.cpp:149 |
570 | msgid "Dubstep" |
571 | msgstr "Dubstep" |
572 | |
573 | -#: ../src/scope/query.cpp:114 |
574 | +#: ../src/scope/query.cpp:150 |
575 | msgid "Electro" |
576 | msgstr "Electro" |
577 | |
578 | -#: ../src/scope/query.cpp:114 |
579 | +#: ../src/scope/query.cpp:150 |
580 | msgid "Electronic" |
581 | msgstr "Electronic" |
582 | |
583 | -#: ../src/scope/query.cpp:98 |
584 | +#: ../src/scope/query.cpp:134 |
585 | msgid "Entertainment" |
586 | msgstr "Entertainment" |
587 | |
588 | -#: ../src/scope/query.cpp:220 |
589 | +#: ../src/scope/query.cpp:273 |
590 | msgid "Explore" |
591 | msgstr "Explore" |
592 | |
593 | -#: ../src/scope/query.cpp:114 |
594 | +#: ../src/scope/query.cpp:150 |
595 | msgid "Folk" |
596 | msgstr "Folk" |
597 | |
598 | -#: ../src/scope/query.cpp:114 |
599 | +#: ../src/scope/preview.cpp:249 |
600 | +msgid "Follow" |
601 | +msgstr "" |
602 | + |
603 | +#: ../src/scope/preview.cpp:105 |
604 | +msgid "Get my tracks" |
605 | +msgstr "" |
606 | + |
607 | +#: ../src/scope/preview.cpp:219 |
608 | +msgid "Get user tracks" |
609 | +msgstr "" |
610 | + |
611 | +#: ../src/scope/query.cpp:150 |
612 | msgid "Hardcore Techno" |
613 | msgstr "Hardcore Techno" |
614 | |
615 | -#: ../src/scope/query.cpp:115 |
616 | +#: ../src/scope/query.cpp:151 |
617 | msgid "Hip Hop" |
618 | msgstr "Hip Hop" |
619 | |
620 | -#: ../src/scope/query.cpp:111 |
621 | +#: ../src/scope/query.cpp:147 |
622 | msgid "Home" |
623 | msgstr "Home" |
624 | |
625 | -#: ../src/scope/query.cpp:115 |
626 | +#: ../src/scope/query.cpp:151 |
627 | msgid "House" |
628 | msgstr "House" |
629 | |
630 | -#: ../src/scope/query.cpp:115 |
631 | +#: ../src/scope/query.cpp:151 |
632 | msgid "Indie Rock" |
633 | msgstr "Indie Rock" |
634 | |
635 | -#: ../src/scope/query.cpp:115 |
636 | +#: ../src/scope/query.cpp:151 |
637 | msgid "Jazz" |
638 | msgstr "Jazz" |
639 | |
640 | -#: ../src/scope/query.cpp:115 |
641 | +#: ../src/scope/query.cpp:151 |
642 | msgid "Latin" |
643 | msgstr "Latin" |
644 | |
645 | -#: ../src/scope/query.cpp:98 |
646 | +#: ../src/scope/query.cpp:134 |
647 | msgid "Learning" |
648 | msgstr "Learning" |
649 | |
650 | -#: ../src/scope/query.cpp:306 |
651 | +#: ../src/scope/preview.cpp:234 |
652 | +msgid "Like" |
653 | +msgstr "" |
654 | + |
655 | +#: ../src/scope/query.cpp:459 |
656 | msgid "Log-in to SoundCloud" |
657 | msgstr "Log in to SoundCloud" |
658 | |
659 | -#: ../src/scope/query.cpp:116 |
660 | +#: ../src/scope/preview.cpp:163 |
661 | +#, fuzzy |
662 | +msgid "Login to soundcloud" |
663 | +msgstr "Log in to SoundCloud" |
664 | + |
665 | +#: ../src/scope/query.cpp:152 |
666 | msgid "Metal" |
667 | msgstr "Metal" |
668 | |
669 | -#: ../src/scope/query.cpp:116 |
670 | +#: ../src/scope/query.cpp:152 |
671 | msgid "Minimal Techno" |
672 | msgstr "Minimal Techno" |
673 | |
674 | -#: ../src/scope/query.cpp:99 |
675 | +#: ../src/scope/query.cpp:172 |
676 | +msgid "My favorites" |
677 | +msgstr "" |
678 | + |
679 | +#: ../src/scope/query.cpp:135 |
680 | msgid "News & Politics" |
681 | msgstr "News & Politics" |
682 | |
683 | -#: ../src/scope/query.cpp:116 |
684 | +#: ../src/scope/query.cpp:445 |
685 | +msgid "No tracks can be found" |
686 | +msgstr "" |
687 | + |
688 | +#: ../src/scope/query.cpp:152 |
689 | msgid "Piano" |
690 | msgstr "Piano" |
691 | |
692 | -#: ../src/scope/preview.cpp:103 |
693 | +#: ../src/scope/preview.cpp:213 |
694 | msgid "Play in browser" |
695 | msgstr "Play in browser" |
696 | |
697 | -#: ../src/scope/query.cpp:116 |
698 | +#: ../src/scope/preview.cpp:155 |
699 | +msgid "Please login to post a comment " |
700 | +msgstr "" |
701 | + |
702 | +#: ../src/scope/query.cpp:152 |
703 | msgid "Pop" |
704 | msgstr "Pop" |
705 | |
706 | -#: ../src/scope/query.cpp:117 |
707 | +#: ../src/scope/preview.cpp:187 |
708 | +msgid "Post" |
709 | +msgstr "" |
710 | + |
711 | +#: ../src/scope/query.cpp:153 |
712 | msgid "Progressive House" |
713 | msgstr "Progressive House" |
714 | |
715 | -#: ../src/scope/query.cpp:117 |
716 | +#: ../src/scope/query.cpp:153 |
717 | msgid "Punk" |
718 | msgstr "Punk" |
719 | |
720 | -#: ../src/scope/query.cpp:117 |
721 | +#: ../src/scope/query.cpp:153 |
722 | msgid "R&B" |
723 | msgstr "R&B" |
724 | |
725 | -#: ../src/scope/query.cpp:117 |
726 | +#: ../src/scope/query.cpp:153 |
727 | msgid "Rap" |
728 | msgstr "Rap" |
729 | |
730 | -#: ../src/scope/query.cpp:118 |
731 | +#: ../src/scope/query.cpp:154 |
732 | msgid "Reggae" |
733 | msgstr "Reggae" |
734 | |
735 | -#: ../src/scope/query.cpp:99 |
736 | +#: ../src/scope/query.cpp:135 |
737 | msgid "Religion & Spirituality" |
738 | msgstr "Religion & Spirituality" |
739 | |
740 | -#: ../src/scope/query.cpp:118 |
741 | +#: ../src/scope/preview.cpp:229 |
742 | +msgid "Remove 'Like'" |
743 | +msgstr "" |
744 | + |
745 | +#: ../src/scope/query.cpp:154 |
746 | msgid "Rock" |
747 | msgstr "Rock" |
748 | |
749 | -#: ../src/scope/query.cpp:99 |
750 | +#: ../src/scope/query.cpp:135 |
751 | msgid "Science" |
752 | msgstr "Science" |
753 | |
754 | -#: ../src/scope/query.cpp:118 |
755 | +#: ../src/scope/query.cpp:154 |
756 | msgid "Singer-Songwriter" |
757 | msgstr "Singer-Songwriter" |
758 | |
759 | -#: ../src/scope/query.cpp:118 |
760 | +#: ../src/scope/query.cpp:154 |
761 | msgid "Soul" |
762 | msgstr "Soul" |
763 | |
764 | -#: ../data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in.h:1 |
765 | -msgid "SoundCloud" |
766 | -msgstr "SoundCloud" |
767 | - |
768 | -#: ../data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in.h:2 |
769 | -msgid "SoundCloud scope for Unity8" |
770 | -msgstr "SoundCloud scope for Unity8" |
771 | - |
772 | -#: ../src/scope/query.cpp:100 |
773 | +#: ../src/scope/query.cpp:136 |
774 | msgid "Sports" |
775 | msgstr "Sports" |
776 | |
777 | -#: ../src/scope/query.cpp:100 |
778 | +#: ../src/scope/query.cpp:136 |
779 | msgid "Storytelling" |
780 | msgstr "Storytelling" |
781 | |
782 | -#: ../src/scope/query.cpp:208 |
783 | +#: ../src/scope/query.cpp:260 |
784 | msgid "Stream" |
785 | msgstr "Stream" |
786 | |
787 | -#: ../src/scope/query.cpp:119 |
788 | +#: ../src/scope/query.cpp:155 |
789 | msgid "Tech House" |
790 | msgstr "Tech House" |
791 | |
792 | -#: ../src/scope/query.cpp:119 |
793 | +#: ../src/scope/query.cpp:155 |
794 | msgid "Techno" |
795 | msgstr "Techno" |
796 | |
797 | -#: ../src/scope/query.cpp:100 |
798 | +#: ../src/scope/query.cpp:136 |
799 | msgid "Technology" |
800 | msgstr "Technology" |
801 | |
802 | -#: ../src/scope/query.cpp:119 |
803 | +#: ../src/scope/query.cpp:155 |
804 | msgid "Trance" |
805 | msgstr "Trance" |
806 | |
807 | -#: ../src/scope/query.cpp:119 |
808 | +#: ../src/scope/query.cpp:155 |
809 | msgid "Trap" |
810 | msgstr "Trap" |
811 | |
812 | -#: ../src/scope/query.cpp:120 |
813 | +#: ../src/scope/query.cpp:156 |
814 | msgid "Trip Hop" |
815 | msgstr "Trip Hop" |
816 | |
817 | -#: ../src/scope/preview.cpp:94 |
818 | +#: ../src/scope/preview.cpp:244 |
819 | +msgid "Unfollow" |
820 | +msgstr "" |
821 | + |
822 | +#: ../src/scope/preview.cpp:100 |
823 | +#, fuzzy |
824 | +msgid "View in browser" |
825 | +msgstr "Play in browser" |
826 | + |
827 | +#: ../src/scope/preview.cpp:206 |
828 | msgid "Watch video" |
829 | msgstr "Watch video" |
830 | |
831 | -#: ../src/scope/query.cpp:120 |
832 | +#: ../src/scope/query.cpp:156 |
833 | msgid "World" |
834 | msgstr "World" |
835 | + |
836 | +#: ../src/scope/query.cpp:380 |
837 | +msgid "create time" |
838 | +msgstr "" |
839 | + |
840 | +#: ../src/scope/query.cpp:381 |
841 | +msgid "genre" |
842 | +msgstr "" |
843 | + |
844 | +#: ../src/scope/query.cpp:382 |
845 | +msgid "license" |
846 | +msgstr "" |
847 | + |
848 | +#: ../src/scope/preview.cpp:162 |
849 | +msgid "open" |
850 | +msgstr "" |
851 | + |
852 | +#: ../src/scope/query.cpp:399 |
853 | +msgid "track" |
854 | +msgstr "" |
855 | + |
856 | +#: ../src/scope/preview.cpp:68 ../src/scope/query.cpp:431 |
857 | +msgid "user" |
858 | +msgstr "" |
859 | + |
860 | +#~ msgid "SoundCloud" |
861 | +#~ msgstr "SoundCloud" |
862 | + |
863 | +#~ msgid "SoundCloud scope for Unity8" |
864 | +#~ msgstr "SoundCloud scope for Unity8" |
865 | |
866 | === modified file 'po/unity-scope-soundcloud.pot' |
867 | --- po/unity-scope-soundcloud.pot 2014-11-18 15:08:53 +0000 |
868 | +++ po/unity-scope-soundcloud.pot 2016-02-02 11:41:52 +0000 |
869 | @@ -6,9 +6,9 @@ |
870 | #, fuzzy |
871 | msgid "" |
872 | msgstr "" |
873 | -"Project-Id-Version: unity-scope-soundcloud\n" |
874 | +"Project-Id-Version: PACKAGE VERSION\n" |
875 | "Report-Msgid-Bugs-To: \n" |
876 | -"POT-Creation-Date: 2014-11-18 15:06+0000\n" |
877 | +"POT-Creation-Date: 2016-01-26 16:59+0800\n" |
878 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
879 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
880 | "Language-Team: LANGUAGE <LL@li.org>\n" |
881 | @@ -17,226 +17,302 @@ |
882 | "Content-Type: text/plain; charset=CHARSET\n" |
883 | "Content-Transfer-Encoding: 8bit\n" |
884 | |
885 | -#: ../data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in.h:1 |
886 | -msgid "SoundCloud" |
887 | -msgstr "" |
888 | - |
889 | -#: ../data/com.ubuntu.scopes.soundcloud_soundcloud.ini.in.h:2 |
890 | -msgid "SoundCloud scope for Unity8" |
891 | -msgstr "" |
892 | - |
893 | -#: ../src/scope/query.cpp:97 |
894 | +#: ../src/scope/preview.cpp:68 ../src/scope/query.cpp:431 |
895 | +msgid "user" |
896 | +msgstr "" |
897 | + |
898 | +#: ../src/scope/preview.cpp:100 |
899 | +msgid "View in browser" |
900 | +msgstr "" |
901 | + |
902 | +#: ../src/scope/preview.cpp:105 |
903 | +msgid "Get my tracks" |
904 | +msgstr "" |
905 | + |
906 | +#: ../src/scope/preview.cpp:155 |
907 | +msgid "Please login to post a comment " |
908 | +msgstr "" |
909 | + |
910 | +#: ../src/scope/preview.cpp:162 |
911 | +msgid "open" |
912 | +msgstr "" |
913 | + |
914 | +#: ../src/scope/preview.cpp:163 |
915 | +msgid "Login to soundcloud" |
916 | +msgstr "" |
917 | + |
918 | +#: ../src/scope/preview.cpp:187 |
919 | +msgid "Post" |
920 | +msgstr "" |
921 | + |
922 | +#: ../src/scope/preview.cpp:198 |
923 | +msgid "Buy" |
924 | +msgstr "" |
925 | + |
926 | +#: ../src/scope/preview.cpp:206 |
927 | +msgid "Watch video" |
928 | +msgstr "" |
929 | + |
930 | +#: ../src/scope/preview.cpp:213 |
931 | +msgid "Play in browser" |
932 | +msgstr "" |
933 | + |
934 | +#: ../src/scope/preview.cpp:219 |
935 | +msgid "Get user tracks" |
936 | +msgstr "" |
937 | + |
938 | +#: ../src/scope/preview.cpp:229 |
939 | +msgid "Remove 'Like'" |
940 | +msgstr "" |
941 | + |
942 | +#: ../src/scope/preview.cpp:234 |
943 | +msgid "Like" |
944 | +msgstr "" |
945 | + |
946 | +#: ../src/scope/preview.cpp:244 |
947 | +msgid "Unfollow" |
948 | +msgstr "" |
949 | + |
950 | +#: ../src/scope/preview.cpp:249 |
951 | +msgid "Follow" |
952 | +msgstr "" |
953 | + |
954 | +#: ../src/scope/query.cpp:133 |
955 | msgid "Audiobooks" |
956 | msgstr "" |
957 | |
958 | -#: ../src/scope/query.cpp:98 |
959 | +#: ../src/scope/query.cpp:134 |
960 | msgid "Business" |
961 | msgstr "" |
962 | |
963 | -#: ../src/scope/query.cpp:98 |
964 | +#: ../src/scope/query.cpp:134 |
965 | msgid "Comedy" |
966 | msgstr "" |
967 | |
968 | -#: ../src/scope/query.cpp:98 |
969 | +#: ../src/scope/query.cpp:134 |
970 | msgid "Entertainment" |
971 | msgstr "" |
972 | |
973 | -#: ../src/scope/query.cpp:98 |
974 | +#: ../src/scope/query.cpp:134 |
975 | msgid "Learning" |
976 | msgstr "" |
977 | |
978 | -#: ../src/scope/query.cpp:99 |
979 | +#: ../src/scope/query.cpp:135 |
980 | msgid "News & Politics" |
981 | msgstr "" |
982 | |
983 | -#: ../src/scope/query.cpp:99 |
984 | +#: ../src/scope/query.cpp:135 |
985 | msgid "Religion & Spirituality" |
986 | msgstr "" |
987 | |
988 | -#: ../src/scope/query.cpp:99 |
989 | +#: ../src/scope/query.cpp:135 |
990 | msgid "Science" |
991 | msgstr "" |
992 | |
993 | -#: ../src/scope/query.cpp:100 |
994 | +#: ../src/scope/query.cpp:136 |
995 | msgid "Sports" |
996 | msgstr "" |
997 | |
998 | -#: ../src/scope/query.cpp:100 |
999 | +#: ../src/scope/query.cpp:136 |
1000 | msgid "Storytelling" |
1001 | msgstr "" |
1002 | |
1003 | -#: ../src/scope/query.cpp:100 |
1004 | +#: ../src/scope/query.cpp:136 |
1005 | msgid "Technology" |
1006 | msgstr "" |
1007 | |
1008 | -#: ../src/scope/query.cpp:111 |
1009 | +#: ../src/scope/query.cpp:147 |
1010 | msgid "Home" |
1011 | msgstr "" |
1012 | |
1013 | -#: ../src/scope/query.cpp:112 |
1014 | +#: ../src/scope/query.cpp:148 |
1015 | msgid "Alternative Rock" |
1016 | msgstr "" |
1017 | |
1018 | -#: ../src/scope/query.cpp:112 |
1019 | +#: ../src/scope/query.cpp:148 |
1020 | msgid "Ambient" |
1021 | msgstr "" |
1022 | |
1023 | -#: ../src/scope/query.cpp:112 |
1024 | +#: ../src/scope/query.cpp:148 |
1025 | msgid "Classical" |
1026 | msgstr "" |
1027 | |
1028 | -#: ../src/scope/query.cpp:112 |
1029 | +#: ../src/scope/query.cpp:148 |
1030 | msgid "Country" |
1031 | msgstr "" |
1032 | |
1033 | -#: ../src/scope/query.cpp:113 |
1034 | +#: ../src/scope/query.cpp:149 |
1035 | msgid "Dance" |
1036 | msgstr "" |
1037 | |
1038 | -#: ../src/scope/query.cpp:113 |
1039 | +#: ../src/scope/query.cpp:149 |
1040 | msgid "Deep House" |
1041 | msgstr "" |
1042 | |
1043 | -#: ../src/scope/query.cpp:113 |
1044 | +#: ../src/scope/query.cpp:149 |
1045 | msgid "Disco" |
1046 | msgstr "" |
1047 | |
1048 | -#: ../src/scope/query.cpp:113 |
1049 | +#: ../src/scope/query.cpp:149 |
1050 | msgid "Drum & Bass" |
1051 | msgstr "" |
1052 | |
1053 | -#: ../src/scope/query.cpp:113 |
1054 | +#: ../src/scope/query.cpp:149 |
1055 | msgid "Dubstep" |
1056 | msgstr "" |
1057 | |
1058 | -#: ../src/scope/query.cpp:114 |
1059 | +#: ../src/scope/query.cpp:150 |
1060 | msgid "Electro" |
1061 | msgstr "" |
1062 | |
1063 | -#: ../src/scope/query.cpp:114 |
1064 | +#: ../src/scope/query.cpp:150 |
1065 | msgid "Electronic" |
1066 | msgstr "" |
1067 | |
1068 | -#: ../src/scope/query.cpp:114 |
1069 | +#: ../src/scope/query.cpp:150 |
1070 | msgid "Folk" |
1071 | msgstr "" |
1072 | |
1073 | -#: ../src/scope/query.cpp:114 |
1074 | +#: ../src/scope/query.cpp:150 |
1075 | msgid "Hardcore Techno" |
1076 | msgstr "" |
1077 | |
1078 | -#: ../src/scope/query.cpp:115 |
1079 | +#: ../src/scope/query.cpp:151 |
1080 | msgid "Hip Hop" |
1081 | msgstr "" |
1082 | |
1083 | -#: ../src/scope/query.cpp:115 |
1084 | +#: ../src/scope/query.cpp:151 |
1085 | msgid "House" |
1086 | msgstr "" |
1087 | |
1088 | -#: ../src/scope/query.cpp:115 |
1089 | +#: ../src/scope/query.cpp:151 |
1090 | msgid "Indie Rock" |
1091 | msgstr "" |
1092 | |
1093 | -#: ../src/scope/query.cpp:115 |
1094 | +#: ../src/scope/query.cpp:151 |
1095 | msgid "Jazz" |
1096 | msgstr "" |
1097 | |
1098 | -#: ../src/scope/query.cpp:115 |
1099 | +#: ../src/scope/query.cpp:151 |
1100 | msgid "Latin" |
1101 | msgstr "" |
1102 | |
1103 | -#: ../src/scope/query.cpp:116 |
1104 | +#: ../src/scope/query.cpp:152 |
1105 | msgid "Metal" |
1106 | msgstr "" |
1107 | |
1108 | -#: ../src/scope/query.cpp:116 |
1109 | +#: ../src/scope/query.cpp:152 |
1110 | msgid "Minimal Techno" |
1111 | msgstr "" |
1112 | |
1113 | -#: ../src/scope/query.cpp:116 |
1114 | +#: ../src/scope/query.cpp:152 |
1115 | msgid "Piano" |
1116 | msgstr "" |
1117 | |
1118 | -#: ../src/scope/query.cpp:116 |
1119 | +#: ../src/scope/query.cpp:152 |
1120 | msgid "Pop" |
1121 | msgstr "" |
1122 | |
1123 | -#: ../src/scope/query.cpp:117 |
1124 | +#: ../src/scope/query.cpp:153 |
1125 | msgid "Progressive House" |
1126 | msgstr "" |
1127 | |
1128 | -#: ../src/scope/query.cpp:117 |
1129 | +#: ../src/scope/query.cpp:153 |
1130 | msgid "Punk" |
1131 | msgstr "" |
1132 | |
1133 | -#: ../src/scope/query.cpp:117 |
1134 | +#: ../src/scope/query.cpp:153 |
1135 | msgid "R&B" |
1136 | msgstr "" |
1137 | |
1138 | -#: ../src/scope/query.cpp:117 |
1139 | +#: ../src/scope/query.cpp:153 |
1140 | msgid "Rap" |
1141 | msgstr "" |
1142 | |
1143 | -#: ../src/scope/query.cpp:118 |
1144 | +#: ../src/scope/query.cpp:154 |
1145 | msgid "Reggae" |
1146 | msgstr "" |
1147 | |
1148 | -#: ../src/scope/query.cpp:118 |
1149 | +#: ../src/scope/query.cpp:154 |
1150 | msgid "Rock" |
1151 | msgstr "" |
1152 | |
1153 | -#: ../src/scope/query.cpp:118 |
1154 | +#: ../src/scope/query.cpp:154 |
1155 | msgid "Singer-Songwriter" |
1156 | msgstr "" |
1157 | |
1158 | -#: ../src/scope/query.cpp:118 |
1159 | +#: ../src/scope/query.cpp:154 |
1160 | msgid "Soul" |
1161 | msgstr "" |
1162 | |
1163 | -#: ../src/scope/query.cpp:119 |
1164 | +#: ../src/scope/query.cpp:155 |
1165 | msgid "Tech House" |
1166 | msgstr "" |
1167 | |
1168 | -#: ../src/scope/query.cpp:119 |
1169 | +#: ../src/scope/query.cpp:155 |
1170 | msgid "Techno" |
1171 | msgstr "" |
1172 | |
1173 | -#: ../src/scope/query.cpp:119 |
1174 | +#: ../src/scope/query.cpp:155 |
1175 | msgid "Trance" |
1176 | msgstr "" |
1177 | |
1178 | -#: ../src/scope/query.cpp:119 |
1179 | +#: ../src/scope/query.cpp:155 |
1180 | msgid "Trap" |
1181 | msgstr "" |
1182 | |
1183 | -#: ../src/scope/query.cpp:120 |
1184 | +#: ../src/scope/query.cpp:156 |
1185 | msgid "Trip Hop" |
1186 | msgstr "" |
1187 | |
1188 | -#: ../src/scope/query.cpp:120 |
1189 | +#: ../src/scope/query.cpp:156 |
1190 | msgid "World" |
1191 | msgstr "" |
1192 | |
1193 | -#: ../src/scope/query.cpp:208 |
1194 | +#: ../src/scope/query.cpp:172 |
1195 | +msgid "My favorites" |
1196 | +msgstr "" |
1197 | + |
1198 | +#: ../src/scope/query.cpp:260 |
1199 | msgid "Stream" |
1200 | msgstr "" |
1201 | |
1202 | -#: ../src/scope/query.cpp:220 |
1203 | +#: ../src/scope/query.cpp:273 |
1204 | msgid "Explore" |
1205 | msgstr "" |
1206 | |
1207 | -#: ../src/scope/query.cpp:306 |
1208 | +#: ../src/scope/query.cpp:380 |
1209 | +msgid "create time" |
1210 | +msgstr "" |
1211 | + |
1212 | +#: ../src/scope/query.cpp:381 |
1213 | +msgid "genre" |
1214 | +msgstr "" |
1215 | + |
1216 | +#: ../src/scope/query.cpp:382 |
1217 | +msgid "license" |
1218 | +msgstr "" |
1219 | + |
1220 | +#: ../src/scope/query.cpp:399 |
1221 | +msgid "track" |
1222 | +msgstr "" |
1223 | + |
1224 | +#: ../src/scope/query.cpp:415 |
1225 | +msgid "</b> tracks" |
1226 | +msgstr "" |
1227 | + |
1228 | +#: ../src/scope/query.cpp:416 |
1229 | +msgid "</b> followers" |
1230 | +msgstr "" |
1231 | + |
1232 | +#: ../src/scope/query.cpp:417 |
1233 | +msgid "</b> followings" |
1234 | +msgstr "" |
1235 | + |
1236 | +#: ../src/scope/query.cpp:445 |
1237 | +msgid "No tracks can be found" |
1238 | +msgstr "" |
1239 | + |
1240 | +#: ../src/scope/query.cpp:459 |
1241 | msgid "Log-in to SoundCloud" |
1242 | msgstr "" |
1243 | - |
1244 | -#: ../src/scope/preview.cpp:84 |
1245 | -msgid "Buy" |
1246 | -msgstr "" |
1247 | - |
1248 | -#: ../src/scope/preview.cpp:94 |
1249 | -msgid "Watch video" |
1250 | -msgstr "" |
1251 | - |
1252 | -#: ../src/scope/preview.cpp:103 |
1253 | -msgid "Play in browser" |
1254 | -msgstr "" |
1255 | |
1256 | === modified file 'src/CMakeLists.txt' |
1257 | --- src/CMakeLists.txt 2014-11-18 15:08:53 +0000 |
1258 | +++ src/CMakeLists.txt 2016-02-02 11:41:52 +0000 |
1259 | @@ -32,9 +32,11 @@ |
1260 | api/client.cpp |
1261 | api/track.cpp |
1262 | api/user.cpp |
1263 | + api/comment.cpp |
1264 | scope/preview.cpp |
1265 | scope/query.cpp |
1266 | scope/scope.cpp |
1267 | + scope/activation.cpp |
1268 | ) |
1269 | |
1270 | # Find all the headers |
1271 | |
1272 | === modified file 'src/api/client.cpp' |
1273 | --- src/api/client.cpp 2014-12-04 14:09:22 +0000 |
1274 | +++ src/api/client.cpp 2016-02-02 11:41:52 +0000 |
1275 | @@ -14,13 +14,16 @@ |
1276 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1277 | * |
1278 | * Author: Pete Woods <pete.woods@canonical.com> |
1279 | + * Gary Wang <gary.wang@canonical.com> |
1280 | */ |
1281 | |
1282 | #include <api/client.h> |
1283 | #include <api/track.h> |
1284 | +#include <api/comment.h> |
1285 | |
1286 | #include <boost/iostreams/filtering_stream.hpp> |
1287 | #include <boost/iostreams/filter/gzip.hpp> |
1288 | +#include <boost/algorithm/string.hpp> |
1289 | #include <core/net/error.h> |
1290 | #include <core/net/http/client.h> |
1291 | #include <core/net/http/content_type.h> |
1292 | @@ -70,6 +73,26 @@ |
1293 | return results; |
1294 | } |
1295 | |
1296 | +template<typename T> |
1297 | +static T get_typed_authuser_info(const string &filter, const json::Value &root) { |
1298 | + T results((json::Value())); |
1299 | + |
1300 | + string kind = root["kind"].asString(); |
1301 | + |
1302 | + if (kind == filter) { |
1303 | + return T(root); |
1304 | + } |
1305 | + return results; |
1306 | +} |
1307 | + |
1308 | +template<typename T> |
1309 | +static T is_successful(const json::Value &root) { |
1310 | + T results = (boost::algorithm::contains(root["status"].asString(), "201") |
1311 | + || boost::algorithm::contains(root["status"].asString(), "200") |
1312 | + || root["id"].asUInt() > 0); |
1313 | + return results; |
1314 | +} |
1315 | + |
1316 | } |
1317 | |
1318 | class Client::Priv { |
1319 | @@ -101,6 +124,55 @@ |
1320 | const net::Uri::QueryParameters ¶meters, |
1321 | http::Request::Handler &handler) { |
1322 | std::lock_guard<std::mutex> lock(config_mutex_); |
1323 | + http::Request::Configuration configuration = net_config(path, parameters); |
1324 | + configuration.header.add("User-Agent", config_.user_agent + " (gzip)"); |
1325 | + configuration.header.add("Accept-Encoding", "gzip"); |
1326 | + |
1327 | + auto request = client_->head(configuration); |
1328 | + request->async_execute(handler); |
1329 | + } |
1330 | + |
1331 | + void post(const net::Uri::Path &path, |
1332 | + const net::Uri::QueryParameters ¶meters, |
1333 | + const std::string &postmsg, |
1334 | + const std::string &content_type, |
1335 | + http::Request::Handler &handler) { |
1336 | + std::lock_guard<std::mutex> lock(config_mutex_); |
1337 | + http::Request::Configuration configuration = net_config(path, parameters); |
1338 | + configuration.header.add("User-Agent", config_.user_agent); |
1339 | + configuration.header.add("Content-Type", content_type); |
1340 | + |
1341 | + auto request = client_->post(configuration, postmsg, content_type); |
1342 | + request->async_execute(handler); |
1343 | + } |
1344 | + |
1345 | + void put(const net::Uri::Path &path, |
1346 | + const net::Uri::QueryParameters ¶meters, |
1347 | + const std::string &postmsg, |
1348 | + http::Request::Handler &handler) { |
1349 | + std::lock_guard<std::mutex> lock(config_mutex_); |
1350 | + http::Request::Configuration configuration = net_config(path, parameters); |
1351 | + configuration.header.add("User-Agent", config_.user_agent); |
1352 | + std::istringstream is(postmsg); |
1353 | + |
1354 | + auto request = client_->put(configuration, is, postmsg.length()); |
1355 | + request->async_execute(handler); |
1356 | + } |
1357 | + |
1358 | + void del(const net::Uri::Path &path, |
1359 | + const net::Uri::QueryParameters ¶meters, |
1360 | + http::Request::Handler &handler) { |
1361 | + std::lock_guard<std::mutex> lock(config_mutex_); |
1362 | + http::Request::Configuration configuration = net_config(path, parameters); |
1363 | + configuration.header.add("User-Agent", config_.user_agent); |
1364 | + configuration.header.add("X-HTTP-Method-Override", "DELETE"); |
1365 | + |
1366 | + auto request = client_->post(configuration, "", ""); |
1367 | + request->async_execute(handler); |
1368 | + } |
1369 | + |
1370 | + http::Request::Configuration net_config(const net::Uri::Path &path, |
1371 | + const net::Uri::QueryParameters ¶meters) { |
1372 | update_config(); |
1373 | |
1374 | http::Request::Configuration configuration; |
1375 | @@ -115,12 +187,9 @@ |
1376 | net::Uri uri = net::make_uri(config_.apiroot, path, |
1377 | complete_parameters); |
1378 | configuration.uri = client_->uri_to_string(uri); |
1379 | - configuration.header.add("User-Agent", config_.user_agent + " (gzip)"); |
1380 | - configuration.header.add("Accept-Encoding", "gzip"); |
1381 | |
1382 | - auto request = client_->head(configuration); |
1383 | - request->async_execute(handler); |
1384 | - } |
1385 | + return configuration; |
1386 | + } |
1387 | |
1388 | http::Request::Progress::Next progress_report( |
1389 | const http::Request::Progress&) { |
1390 | @@ -164,11 +233,13 @@ |
1391 | json::Reader reader; |
1392 | reader.parse(decompressed, root); |
1393 | |
1394 | - if (response.status != http::Status::ok) { |
1395 | - prom->set_exception(make_exception_ptr(domain_error(root["error"].asString()))); |
1396 | - } else { |
1397 | + //Soundcloud api return 404 if track is not in auth user's favorite list |
1398 | + //or auth user is not following one certain user. |
1399 | +// if (response.status != http::Status::ok) { |
1400 | +// prom->set_exception(make_exception_ptr(domain_error(root["error"].asString()))); |
1401 | +// } else { |
1402 | prom->set_value(func(root)); |
1403 | - } |
1404 | +// } |
1405 | }); |
1406 | |
1407 | get(path, parameters, handler); |
1408 | @@ -176,6 +247,108 @@ |
1409 | return prom->get_future(); |
1410 | } |
1411 | |
1412 | + template<typename T> |
1413 | + future<T> async_post(const net::Uri::Path &path, |
1414 | + const net::Uri::QueryParameters ¶meters, |
1415 | + const std::string &postmsg, |
1416 | + const std::string &content_type, |
1417 | + const function<T(const json::Value &root)> &func) { |
1418 | + auto prom = make_shared<promise<T>>(); |
1419 | + |
1420 | + http::Request::Handler handler; |
1421 | + handler.on_progress( |
1422 | + bind(&Client::Priv::progress_report, this, placeholders::_1)); |
1423 | + handler.on_error([prom](const net::Error& e) |
1424 | + { |
1425 | + prom->set_exception(make_exception_ptr(e)); |
1426 | + }); |
1427 | + handler.on_response( |
1428 | + [prom,func](const http::Response& response) |
1429 | + { |
1430 | + json::Value root; |
1431 | + json::Reader reader; |
1432 | + reader.parse(response.body, root); |
1433 | + |
1434 | + if (response.status != http::Status::ok && |
1435 | + response.status != http::Status::created) { |
1436 | + prom->set_exception(make_exception_ptr(domain_error(root["error"].asString()))); |
1437 | + } else { |
1438 | + prom->set_value(func(root)); |
1439 | + } |
1440 | + }); |
1441 | + |
1442 | + post(path, parameters, postmsg, content_type, handler); |
1443 | + |
1444 | + return prom->get_future(); |
1445 | + } |
1446 | + |
1447 | + template<typename T> |
1448 | + future<T> async_put(const net::Uri::Path &path, |
1449 | + const net::Uri::QueryParameters ¶meters, |
1450 | + const std::string &msg, |
1451 | + const function<T(const json::Value &root)> &func) { |
1452 | + auto prom = make_shared<promise<T>>(); |
1453 | + |
1454 | + http::Request::Handler handler; |
1455 | + handler.on_progress( |
1456 | + bind(&Client::Priv::progress_report, this, placeholders::_1)); |
1457 | + handler.on_error([prom](const net::Error& e) |
1458 | + { |
1459 | + prom->set_exception(make_exception_ptr(e)); |
1460 | + }); |
1461 | + handler.on_response( |
1462 | + [prom,func](const http::Response& response) |
1463 | + { |
1464 | + json::Value root; |
1465 | + json::Reader reader; |
1466 | + reader.parse(response.body, root); |
1467 | + |
1468 | + if (response.status != http::Status::created && |
1469 | + response.status != http::Status::ok) { |
1470 | + prom->set_exception(make_exception_ptr(domain_error(root["error"].asString()))); |
1471 | + } else { |
1472 | + prom->set_value(func(root)); |
1473 | + } |
1474 | + }); |
1475 | + |
1476 | + put(path, parameters, msg, handler); |
1477 | + |
1478 | + return prom->get_future(); |
1479 | + } |
1480 | + |
1481 | + template<typename T> |
1482 | + future<T> async_del(const net::Uri::Path &path, |
1483 | + const net::Uri::QueryParameters ¶meters, |
1484 | + const function<T(const json::Value &root)> &func) { |
1485 | + auto prom = make_shared<promise<T>>(); |
1486 | + |
1487 | + http::Request::Handler handler; |
1488 | + handler.on_progress( |
1489 | + bind(&Client::Priv::progress_report, this, placeholders::_1)); |
1490 | + handler.on_error([prom](const net::Error& e) |
1491 | + { |
1492 | + prom->set_exception(make_exception_ptr(e)); |
1493 | + }); |
1494 | + handler.on_response( |
1495 | + [prom,func](const http::Response& response) |
1496 | + { |
1497 | + json::Value root; |
1498 | + json::Reader reader; |
1499 | + reader.parse(response.body, root); |
1500 | + |
1501 | + if (response.status != http::Status::created && |
1502 | + response.status != http::Status::ok) { |
1503 | + prom->set_exception(make_exception_ptr(domain_error(root["error"].asString()))); |
1504 | + } else { |
1505 | + prom->set_value(func(root)); |
1506 | + } |
1507 | + }); |
1508 | + |
1509 | + del(path, parameters, handler); |
1510 | + |
1511 | + return prom->get_future(); |
1512 | + } |
1513 | + |
1514 | std::string client_id() { |
1515 | std::lock_guard<std::mutex> lock(config_mutex_); |
1516 | update_config(); |
1517 | @@ -277,6 +450,147 @@ |
1518 | }); |
1519 | } |
1520 | |
1521 | +future<deque<Comment>> Client::track_comments(const std::string &trackid) { |
1522 | + net::Uri::QueryParameters params; |
1523 | + |
1524 | + return p->async_get<deque<Comment>>( |
1525 | + { "tracks", trackid, "comments.json"}, params, |
1526 | + [](const json::Value &root) { |
1527 | + auto results = get_typed_list<Comment>("comment", root); |
1528 | + return results; |
1529 | + }); |
1530 | +} |
1531 | + |
1532 | +future<bool> Client::post_comment(const std::string &trackid, |
1533 | + const std::string &postmsg) { |
1534 | + net::Uri::QueryParameters params; |
1535 | + |
1536 | + string postbody = "<comment><body>"+ postmsg + "</body></comment>"; |
1537 | + std::string content_type = "application/xml"; |
1538 | + return p->async_post<bool>( |
1539 | + { "tracks", trackid, "comments.json"}, params, postbody, content_type, |
1540 | + [](const json::Value &root) { |
1541 | + auto results = is_successful<bool>(root); |
1542 | + return results; |
1543 | + }); |
1544 | +} |
1545 | + |
1546 | +std::future<std::deque<Track> > Client::favorite_tracks() |
1547 | +{ |
1548 | + net::Uri::QueryParameters params; |
1549 | + |
1550 | + return p->async_get<deque<Track>>( |
1551 | + { "me", "favorites.json"}, params, |
1552 | + [](const json::Value &root) { |
1553 | + return get_typed_list<Track>("track", root); |
1554 | + }); |
1555 | +} |
1556 | + |
1557 | +std::future<std::deque<Track> > Client::get_user_tracks(const string &userid, |
1558 | + int limit) |
1559 | +{ |
1560 | + net::Uri::QueryParameters params; |
1561 | + if (limit > 0) { |
1562 | + params.emplace_back("limit", std::to_string(limit)); |
1563 | + } |
1564 | + return p->async_get<deque<Track>>( |
1565 | + { "users", userid, "tracks.json"}, params, |
1566 | + [](const json::Value &root) { |
1567 | + return get_typed_list<Track>("track", root); |
1568 | + }); |
1569 | +} |
1570 | + |
1571 | +future<bool> Client::is_fav_track(const std::string &trackid) { |
1572 | + net::Uri::QueryParameters params; |
1573 | + |
1574 | + return p->async_get<bool>( |
1575 | + { "me", "favorites", trackid}, params, |
1576 | + [](const json::Value &root) { |
1577 | + auto results = is_successful<bool>(root); |
1578 | + return results; |
1579 | + }); |
1580 | +} |
1581 | + |
1582 | +future<bool> Client::like_track(const std::string &trackid) { |
1583 | + net::Uri::QueryParameters params; |
1584 | + |
1585 | + return p->async_put<bool>( |
1586 | + { "me", "favorites", trackid}, params, "", |
1587 | + [](const json::Value &root) { |
1588 | + auto results = is_successful<bool>(root); |
1589 | + return results; |
1590 | + }); |
1591 | +} |
1592 | + |
1593 | +future<bool> Client::delete_like_track(const std::string &trackid) { |
1594 | + net::Uri::QueryParameters params; |
1595 | + |
1596 | + return p->async_del<bool>( |
1597 | + { "me", "favorites", trackid}, params, |
1598 | + [](const json::Value &root) { |
1599 | + auto results = is_successful<bool>(root); |
1600 | + return results; |
1601 | + }); |
1602 | +} |
1603 | + |
1604 | +std::future<bool> Client::is_user_follower(const string &userid) { |
1605 | + net::Uri::QueryParameters params; |
1606 | + |
1607 | + return p->async_get<bool>( |
1608 | + { "me", "followings", userid}, params, |
1609 | + [](const json::Value &root) { |
1610 | + auto results = is_successful<bool>(root); |
1611 | + return results; |
1612 | + }); |
1613 | +} |
1614 | + |
1615 | +future<bool> Client::follow_user(const std::string &userid) { |
1616 | + net::Uri::QueryParameters params; |
1617 | + |
1618 | + return p->async_put<bool>( |
1619 | + { "me", "followings", userid}, params, "", |
1620 | + [](const json::Value &root) { |
1621 | + auto results = is_successful<bool>(root); |
1622 | + return results; |
1623 | + }); |
1624 | +} |
1625 | + |
1626 | +std::future<bool> Client::unfollow_user(const string &userid) |
1627 | +{ |
1628 | + net::Uri::QueryParameters params; |
1629 | + |
1630 | + return p->async_del<bool>( |
1631 | + { "me", "followings", userid}, params, |
1632 | + [](const json::Value &root) { |
1633 | + auto results = is_successful<bool>(root); |
1634 | + return results; |
1635 | + }); |
1636 | +} |
1637 | + |
1638 | +std::future<User> Client::get_authuser_info() |
1639 | +{ |
1640 | + net::Uri::QueryParameters params; |
1641 | + |
1642 | + return p->async_get<User>( |
1643 | + { "me" }, params, |
1644 | + [](const json::Value &root) { |
1645 | + auto results = get_typed_authuser_info<User>("user", root); |
1646 | + return results; |
1647 | + }); |
1648 | +} |
1649 | + |
1650 | +std::future<User> Client::get_user_info(const string &userid) |
1651 | +{ |
1652 | + net::Uri::QueryParameters params; |
1653 | + |
1654 | + return p->async_get<User>( |
1655 | + { "users", userid}, params, |
1656 | + [](const json::Value &root) { |
1657 | + auto results = get_typed_authuser_info<User>("user", root); |
1658 | + return results; |
1659 | + }); |
1660 | +} |
1661 | + |
1662 | void Client::cancel() { |
1663 | p->cancelled_ = true; |
1664 | } |
1665 | |
1666 | === added file 'src/api/comment.cpp' |
1667 | --- src/api/comment.cpp 1970-01-01 00:00:00 +0000 |
1668 | +++ src/api/comment.cpp 2016-02-02 11:41:52 +0000 |
1669 | @@ -0,0 +1,71 @@ |
1670 | +/* |
1671 | + * Copyright (C) 2014 Canonical, Ltd. |
1672 | + * |
1673 | + * This library is free software; you can redistribute it and/or modify it under |
1674 | + * the terms of version 3 of the GNU Lesser General Public License as published |
1675 | + * by the Free Software Foundation. |
1676 | + * |
1677 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
1678 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
1679 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
1680 | + * details. |
1681 | + * |
1682 | + * You should have received a copy of the GNU Lesser General Public License |
1683 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1684 | + * |
1685 | + * Author: Pete Woods <pete.woods@canonical.com> |
1686 | + * Gary Wang <gary.wang@canonical.com> |
1687 | + */ |
1688 | + |
1689 | +#include <boost/algorithm/string.hpp> |
1690 | +#include <api/comment.h> |
1691 | + |
1692 | +#include <json/json.h> |
1693 | + |
1694 | +namespace json = Json; |
1695 | +using namespace api; |
1696 | +using namespace std; |
1697 | + |
1698 | +Comment::Comment(const json::Value &data) : |
1699 | + user_(data["user"]) { |
1700 | + body_ = data["body"].asString(); |
1701 | + created_at_ = data["created_at"].asString(); |
1702 | + |
1703 | + std::vector<std::string> created_time; |
1704 | + boost::split(created_time, created_at_, boost::is_any_of(" ")); |
1705 | + created_at_ = created_time[0]; |
1706 | + |
1707 | + id_ = data["id"].asUInt(); |
1708 | +} |
1709 | + |
1710 | +const unsigned int & Comment::id() const { |
1711 | + return id_; |
1712 | +} |
1713 | + |
1714 | +const string & Comment::body() const { |
1715 | + return body_; |
1716 | +} |
1717 | + |
1718 | +const string & Comment::title() const { |
1719 | + return user_.title(); |
1720 | +} |
1721 | + |
1722 | +const string & Comment::artwork() const { |
1723 | + return user_.artwork(); |
1724 | +} |
1725 | + |
1726 | +const string & Comment::created_at() const { |
1727 | + return created_at_; |
1728 | +} |
1729 | + |
1730 | +const User & Comment::user() const { |
1731 | + return user_; |
1732 | +} |
1733 | + |
1734 | +Resource::Kind Comment::kind() const { |
1735 | + return Resource::Kind::comment; |
1736 | +} |
1737 | + |
1738 | +std::string Comment::kind_str() const { |
1739 | + return "comment"; |
1740 | +} |
1741 | |
1742 | === modified file 'src/api/track.cpp' |
1743 | --- src/api/track.cpp 2014-11-06 11:40:45 +0000 |
1744 | +++ src/api/track.cpp 2016-02-02 11:41:52 +0000 |
1745 | @@ -14,8 +14,10 @@ |
1746 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1747 | * |
1748 | * Author: Pete Woods <pete.woods@canonical.com> |
1749 | + * Gary Wang <gary.wang@canonical.com> |
1750 | */ |
1751 | |
1752 | +#include <boost/algorithm/string.hpp> |
1753 | #include <api/track.h> |
1754 | |
1755 | #include <json/json.h> |
1756 | @@ -33,13 +35,26 @@ |
1757 | duration_ = data["duration"].asUInt(); |
1758 | license_ = data["license"].asString(); |
1759 | created_at_ = data["created_at"].asString(); |
1760 | + |
1761 | + std::vector<std::string> created_time; |
1762 | + boost::split(created_time, created_at_, boost::is_any_of(" ")); |
1763 | + created_at_ = created_time[0]; |
1764 | |
1765 | playback_count_ = data["playback_count"].asUInt(); |
1766 | favoritings_count_ = data["favoritings_count"].asUInt(); |
1767 | + comment_count_ = data["comment_count"].asUInt(); |
1768 | + repost_count_ = data["reposts_count"].asUInt(); |
1769 | + likes_count_ = data["likes_count"].asUInt(); |
1770 | |
1771 | artwork_ = data["artwork_url"].asString(); |
1772 | waveform_ = data["waveform_url"].asString(); |
1773 | - |
1774 | + //when loading login user stream, server gives waveform |
1775 | + //sample json file instread of image |
1776 | + if (boost::algorithm::ends_with(waveform_, "json")) { |
1777 | + boost::replace_all(waveform_, "json", "png"); |
1778 | + boost::replace_all(waveform_, "is.", "1."); |
1779 | + } |
1780 | + |
1781 | streamable_ = data["streamable"].asBool(); |
1782 | downloadable_ = data["downloadable"].asBool(); |
1783 | |
1784 | @@ -48,6 +63,9 @@ |
1785 | stream_url_ = data["stream_url"].asString(); |
1786 | download_url_ = data["download_url"].asString(); |
1787 | video_url_ = data["video_url"].asString(); |
1788 | + |
1789 | + genre_ = data["genre"].asString(); |
1790 | + original_format_ = data["original_format"].asString(); |
1791 | } |
1792 | |
1793 | const string & Track::title() const { |
1794 | @@ -126,6 +144,26 @@ |
1795 | return favoritings_count_; |
1796 | } |
1797 | |
1798 | +unsigned int Track::comment_count() const { |
1799 | + return comment_count_; |
1800 | +} |
1801 | + |
1802 | +unsigned int Track::repost_count() const { |
1803 | + return repost_count_; |
1804 | +} |
1805 | + |
1806 | +unsigned int Track::likes_count() const { |
1807 | + return likes_count_; |
1808 | +} |
1809 | + |
1810 | +const string & Track::genre() const { |
1811 | + return genre_; |
1812 | +} |
1813 | + |
1814 | +const string & Track::original_format() const { |
1815 | + return original_format_; |
1816 | +} |
1817 | + |
1818 | const User & Track::user() const { |
1819 | return user_; |
1820 | } |
1821 | |
1822 | === modified file 'src/api/user.cpp' |
1823 | --- src/api/user.cpp 2014-11-05 16:17:51 +0000 |
1824 | +++ src/api/user.cpp 2016-02-02 11:41:52 +0000 |
1825 | @@ -28,6 +28,11 @@ |
1826 | title_ = data["username"].asString(); |
1827 | id_ = data["id"].asUInt(); |
1828 | artwork_ = data["avatar_url"].asString(); |
1829 | + permalink_ = data["permalink_url"].asString(); |
1830 | + track_count_ = data["track_count"].asUInt(); |
1831 | + followers_count_ = data["followers_count"].asUInt(); |
1832 | + followings_count_ = data["followings_count"].asUInt(); |
1833 | + bio_ = data["description"].asString(); |
1834 | } |
1835 | |
1836 | const string & User::title() const { |
1837 | @@ -38,6 +43,31 @@ |
1838 | return id_; |
1839 | } |
1840 | |
1841 | +const string &User::permalink_url() const |
1842 | +{ |
1843 | + return permalink_; |
1844 | +} |
1845 | + |
1846 | +const unsigned int &User::track_count() const |
1847 | +{ |
1848 | + return track_count_; |
1849 | +} |
1850 | + |
1851 | +const unsigned int &User::followers_count() const |
1852 | +{ |
1853 | + return followers_count_; |
1854 | +} |
1855 | + |
1856 | +const unsigned int &User::followings_count() const |
1857 | +{ |
1858 | + return followings_count_; |
1859 | +} |
1860 | + |
1861 | +const string &User::bio() const |
1862 | +{ |
1863 | + return bio_; |
1864 | +} |
1865 | + |
1866 | const string & User::artwork() const { |
1867 | return artwork_; |
1868 | } |
1869 | |
1870 | === added file 'src/scope/activation.cpp' |
1871 | --- src/scope/activation.cpp 1970-01-01 00:00:00 +0000 |
1872 | +++ src/scope/activation.cpp 2016-02-02 11:41:52 +0000 |
1873 | @@ -0,0 +1,91 @@ |
1874 | +/* |
1875 | + * Copyright (C) 2014 Canonical, Ltd. |
1876 | + * |
1877 | + * This library is free software; you can redistribute it and/or modify it under |
1878 | + * the terms of version 3 of the GNU Lesser General Public License as published |
1879 | + * by the Free Software Foundation. |
1880 | + * |
1881 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
1882 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
1883 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
1884 | + * details. |
1885 | + * |
1886 | + * You should have received a copy of the GNU Lesser General Public License |
1887 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1888 | + * |
1889 | + * Author: Pete Woods <pete.woods@canonical.com> |
1890 | + * Gary Wang <gary.wang@canonical.com> |
1891 | + */ |
1892 | + |
1893 | +#include <scope/activation.h> |
1894 | +#include <unity/scopes/ActivationResponse.h> |
1895 | +#include <unity/scopes/ActionMetadata.h> |
1896 | + |
1897 | +#include <iostream> |
1898 | + |
1899 | +namespace sc = unity::scopes; |
1900 | + |
1901 | +using namespace std; |
1902 | +using namespace scope; |
1903 | +using namespace api; |
1904 | + |
1905 | +template<typename T> |
1906 | +static T get_or_throw(future<T> &f) { |
1907 | + if (f.wait_for(std::chrono::seconds(10)) != future_status::ready) { |
1908 | + throw domain_error("HTTP request timeout"); |
1909 | + } |
1910 | + return f.get(); |
1911 | +} |
1912 | + |
1913 | +Activation::Activation(const sc::Result &result, |
1914 | + const sc::ActionMetadata &metadata, |
1915 | + std::string const& action_id, |
1916 | + std::shared_ptr<sc::OnlineAccountClient> oa_client) : |
1917 | + sc::ActivationQueryBase(result, metadata), |
1918 | + action_id_(action_id), |
1919 | + client_(oa_client) { |
1920 | +} |
1921 | + |
1922 | +sc::ActivationResponse Activation::activate() { |
1923 | + try { |
1924 | + string trackid = result()["id"].get_string(); |
1925 | + string userid = result()["userid"].get_string(); |
1926 | + |
1927 | + if (action_id_ == "commented") { |
1928 | + string comments = action_metadata().scope_data().get_dict()["comment"].get_string(); |
1929 | + future<bool> post_future = client_.post_comment(trackid, comments); |
1930 | + auto status = get_or_throw(post_future); |
1931 | + cout<< "auth user post a comment: " << status << endl; |
1932 | + |
1933 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1934 | + } else if (action_id_ == "like") { |
1935 | + future<bool> like_future = client_.like_track(trackid); |
1936 | + auto status = get_or_throw(like_future); |
1937 | + cout<< "auth user likes track: " << status << endl; |
1938 | + |
1939 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1940 | + } else if (action_id_ == "deletelike") { |
1941 | + future<bool> ret_future = client_.delete_like_track(trackid); |
1942 | + auto status = get_or_throw(ret_future); |
1943 | + cout<< "auth user delete a like track: " << status << endl; |
1944 | + |
1945 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1946 | + } else if (action_id_ == "follow") { |
1947 | + future<bool> follow_future = client_.follow_user(userid); |
1948 | + auto status = get_or_throw(follow_future); |
1949 | + cout<< "auth user follow user: " << status << endl; |
1950 | + |
1951 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1952 | + } else if (action_id_ == "unfollow") { |
1953 | + future<bool> unfollow_future = client_.unfollow_user(userid); |
1954 | + auto status = get_or_throw(unfollow_future); |
1955 | + cout<< "auth user unfollow user: " << status << endl; |
1956 | + |
1957 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1958 | + } |
1959 | + }catch (domain_error &e) { |
1960 | + cerr << e.what() << endl; |
1961 | + return sc::ActivationResponse(sc::ActivationResponse::Status::ShowPreview); |
1962 | + } |
1963 | + return sc::ActivationResponse(sc::ActivationResponse::Status::NotHandled); |
1964 | +} |
1965 | |
1966 | === modified file 'src/scope/preview.cpp' |
1967 | --- src/scope/preview.cpp 2014-11-10 11:54:32 +0000 |
1968 | +++ src/scope/preview.cpp 2016-02-02 11:41:52 +0000 |
1969 | @@ -14,10 +14,15 @@ |
1970 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1971 | * |
1972 | * Author: Pete Woods <pete.woods@canonical.com> |
1973 | + * Gary Wang <gary.wang@canonical.com> |
1974 | */ |
1975 | |
1976 | +#include <boost/algorithm/string.hpp> |
1977 | + |
1978 | #include <scope/localization.h> |
1979 | #include <scope/preview.h> |
1980 | +#include <api/client.h> |
1981 | +#include <api/comment.h> |
1982 | |
1983 | #include <unity/scopes/ColumnLayout.h> |
1984 | #include <unity/scopes/PreviewWidget.h> |
1985 | @@ -31,83 +36,250 @@ |
1986 | |
1987 | using namespace std; |
1988 | using namespace scope; |
1989 | - |
1990 | -Preview::Preview(const sc::Result &result, const sc::ActionMetadata &metadata) : |
1991 | - sc::PreviewQueryBase(result, metadata) { |
1992 | +using namespace api; |
1993 | + |
1994 | +template<typename T> |
1995 | +static T get_or_throw(future<T> &f) { |
1996 | + if (f.wait_for(std::chrono::seconds(10)) != future_status::ready) { |
1997 | + throw domain_error("HTTP request timeout"); |
1998 | + } |
1999 | + return f.get(); |
2000 | +} |
2001 | + |
2002 | +Preview::Preview(const sc::Result &result, const sc::ActionMetadata &metadata, |
2003 | + std::shared_ptr<sc::OnlineAccountClient> oa_client) : |
2004 | + sc::PreviewQueryBase(result, metadata), |
2005 | + client_(oa_client) { |
2006 | } |
2007 | |
2008 | void Preview::cancelled() { |
2009 | } |
2010 | |
2011 | void Preview::run(sc::PreviewReplyProxy const& reply) { |
2012 | - auto const res = result(); |
2013 | - |
2014 | - // Support three different column layouts |
2015 | - sc::ColumnLayout layout1col(1), layout2col(2), layout3col(3); |
2016 | - |
2017 | - // Single column layout |
2018 | - layout1col.add_column( { "header", "art", "statistics", "tracks", "actions", "description" }); |
2019 | - |
2020 | - // Register the layouts we just created |
2021 | - reply->register_layout( { layout1col }); //, layout2col, layout3col |
2022 | - |
2023 | - sc::PreviewWidget header("header", "header"); |
2024 | - header.add_attribute_mapping("title", "title"); |
2025 | - header.add_attribute_mapping("subtitle", "username"); |
2026 | - |
2027 | - sc::PreviewWidget art("art", "image"); |
2028 | - art.add_attribute_mapping("source", "art"); |
2029 | - |
2030 | - sc::PreviewWidget statistics("statistics", "header"); |
2031 | - statistics.add_attribute_value("title", sc::Variant(res["playback-count"].get_string() + " " + res["favoritings-count"].get_string())); |
2032 | - |
2033 | - sc::PreviewWidget tracks("tracks", "audio"); |
2034 | - { |
2035 | - if (res["streamable"].get_bool()) { |
2036 | - sc::VariantBuilder builder; |
2037 | - builder.add_tuple({ |
2038 | - {"title", sc::Variant(res.title())}, |
2039 | - {"source", sc::Variant(res["stream-url"])}, |
2040 | - {"length", res["duration"]} |
2041 | - }); |
2042 | - tracks.add_attribute_value("tracks", builder.end()); |
2043 | - } |
2044 | - } |
2045 | - |
2046 | - sc::PreviewWidget actions("actions", "actions"); |
2047 | - { |
2048 | - string purchase_url = res["purchase-url"].get_string(); |
2049 | - if (!purchase_url.empty()) { |
2050 | - sc::VariantBuilder builder; |
2051 | - builder.add_tuple({ |
2052 | - {"id", sc::Variant("buy")}, |
2053 | - {"label", sc::Variant(_("Buy"))}, |
2054 | - {"uri", sc::Variant(purchase_url)} |
2055 | - }); |
2056 | - actions.add_attribute_value("actions", builder.end()); |
2057 | - } |
2058 | - string video_url = res["video-url"].get_string(); |
2059 | - if (!video_url.empty()) { |
2060 | - sc::VariantBuilder builder; |
2061 | - builder.add_tuple({ |
2062 | - {"id", sc::Variant("video")}, |
2063 | - {"label", sc::Variant(_("Watch video"))}, |
2064 | - {"uri", sc::Variant(video_url)} |
2065 | - }); |
2066 | - actions.add_attribute_value("actions", builder.end()); |
2067 | - } |
2068 | - { |
2069 | - sc::VariantBuilder builder; |
2070 | - builder.add_tuple({ |
2071 | - {"id", sc::Variant("play")}, |
2072 | - {"label", sc::Variant(_("Play in browser"))} |
2073 | - }); |
2074 | - actions.add_attribute_value("actions", builder.end()); |
2075 | - } |
2076 | - } |
2077 | - |
2078 | - sc::PreviewWidget description("description", "text"); |
2079 | - description.add_attribute_mapping("text", "description"); |
2080 | - |
2081 | - reply->push( { header, art, statistics, tracks, actions, description }); |
2082 | + try { |
2083 | + auto const res = result(); |
2084 | + |
2085 | + sc::PreviewWidgetList widgets; |
2086 | + std::vector<std::string> ids; |
2087 | + // Support three different column layouts |
2088 | + sc::ColumnLayout layout1col(1), layout2col(2), layout3col(3); |
2089 | + |
2090 | + string mode = res["mode"].get_string(); |
2091 | + if (mode == _("user")) { |
2092 | + ids = std::vector<std::string>{ "header", "art", "statistics", "description", "actions"}; |
2093 | + sc::PreviewWidget header("header", "header"); |
2094 | + header.add_attribute_mapping("title", "title"); |
2095 | + widgets.emplace_back(header); |
2096 | + |
2097 | + string artwork_url= res["art"].get_string(); |
2098 | + boost::replace_all(artwork_url, "large", "t500x500"); |
2099 | + sc::PreviewWidget art("art", "image"); |
2100 | + art.add_attribute_value("source", sc::Variant(artwork_url)); |
2101 | + widgets.emplace_back(art); |
2102 | + |
2103 | + sc::PreviewWidget statistics("statistics", "header"); |
2104 | + statistics.add_attribute_value("title", sc::Variant( |
2105 | + res["track-count"].get_string() + " " + |
2106 | + res["followers-count"].get_string() + " " + |
2107 | + res["followings-count"].get_string())); |
2108 | + widgets.emplace_back(statistics); |
2109 | + |
2110 | + sc::PreviewWidget description("description", "text"); |
2111 | + description.add_attribute_value("text", sc::Variant( |
2112 | + res["permalink-url"].get_string() + "<br>" + |
2113 | + res["bio"].get_string())); |
2114 | + widgets.emplace_back(description); |
2115 | + |
2116 | + std::string userid = res["id"].get_string(); |
2117 | + sc::VariantBuilder builder; |
2118 | + sc::PreviewWidget actions("actions", "actions"); |
2119 | + { |
2120 | + string permalink_url = res["permalink-url"].get_string(); |
2121 | + builder.add_tuple({ |
2122 | + {"id", sc::Variant("view")}, |
2123 | + {"label", sc::Variant(_("View in browser"))}, |
2124 | + {"uri", sc::Variant(permalink_url)} |
2125 | + }); |
2126 | + sc::CannedQuery new_query(SCOPE_NAME); |
2127 | + new_query.set_department_id("userid:" + userid); |
2128 | + builder.add_tuple({ |
2129 | + {"id", sc::Variant("usertracks")}, |
2130 | + {"label", sc::Variant(_("Get user tracks"))}, |
2131 | + {"uri", sc::Variant(new_query.to_uri())} |
2132 | + }); |
2133 | + } |
2134 | + actions.add_attribute_value("actions", builder.end()); |
2135 | + widgets.emplace_back(actions); |
2136 | + } else { |
2137 | + ids = std::vector<std::string> { "header", "art", "statistics", "trackinfo", "tracks", "description", "actions"}; |
2138 | + |
2139 | + sc::PreviewWidget header("header", "header"); |
2140 | + header.add_attribute_mapping("title", "title"); |
2141 | + header.add_attribute_mapping("subtitle", "username"); |
2142 | + widgets.emplace_back(header); |
2143 | + |
2144 | + //load big track thubmail |
2145 | + string artwork_url= res["art"].get_string(); |
2146 | + boost::replace_all(artwork_url, "large", "t500x500"); |
2147 | + sc::PreviewWidget art("art", "image"); |
2148 | + art.add_attribute_value("source", sc::Variant(artwork_url)); |
2149 | + widgets.emplace_back(art); |
2150 | + |
2151 | + sc::PreviewWidget statistics("statistics", "header"); |
2152 | + statistics.add_attribute_value("title", sc::Variant( |
2153 | + res["playback-count"].get_string() + " " + |
2154 | + res["likes-count"].get_string() + " " + |
2155 | + res["repost-count"].get_string() + " " + |
2156 | + res["favoritings-count"].get_string() + " " + |
2157 | + res["comment-count"].get_string())); |
2158 | + widgets.emplace_back(statistics); |
2159 | + |
2160 | + std::string trackid = res["id"].get_string(); |
2161 | + std::string userid = res["userid"].get_string(); |
2162 | + |
2163 | + sc::PreviewWidget tracks("tracks", "audio"); |
2164 | + { |
2165 | + if (res["streamable"].get_bool()) { |
2166 | + sc::VariantBuilder builder; |
2167 | + builder.add_tuple({ |
2168 | + {"title", sc::Variant(res.title())}, |
2169 | + {"source", sc::Variant(res["stream-url"])}, |
2170 | + {"length", res["duration"]} |
2171 | + }); |
2172 | + tracks.add_attribute_value("tracks", builder.end()); |
2173 | + widgets.emplace_back(tracks); |
2174 | + } |
2175 | + } |
2176 | + |
2177 | + if (!client_.authenticated()) { |
2178 | + ids.emplace_back("tips-headerid"); |
2179 | + sc::PreviewWidget w_tips(ids.at(ids.size() - 1), "text"); |
2180 | + w_tips.add_attribute_value("text", sc::Variant(_("Please login to post a comment "))); |
2181 | + widgets.emplace_back(w_tips); |
2182 | + |
2183 | + ids.emplace_back("login-actionId"); |
2184 | + sc::PreviewWidget w_action(ids.at(ids.size() - 1), "actions"); |
2185 | + sc::VariantBuilder builder; |
2186 | + builder.add_tuple({ |
2187 | + {"id", sc::Variant(_("open"))}, |
2188 | + {"label", sc::Variant(_("Login to soundcloud"))}, |
2189 | + }); |
2190 | + |
2191 | + sc::OnlineAccountClient oa_client(SCOPE_NAME, "sharing", SCOPE_ACCOUNTS_NAME); |
2192 | + |
2193 | + oa_client.register_account_login_item(w_action, |
2194 | + sc::OnlineAccountClient::InvalidateResults, |
2195 | + sc::OnlineAccountClient::DoNothing); |
2196 | + |
2197 | + w_action.add_attribute_value("actions", builder.end()); |
2198 | + widgets.emplace_back(w_action); |
2199 | + } |
2200 | + |
2201 | + sc::PreviewWidget trackinfo("trackinfo", "table"); |
2202 | + trackinfo.add_attribute_mapping("values", "trackinfo"); |
2203 | + widgets.emplace_back(trackinfo); |
2204 | + |
2205 | + sc::PreviewWidget description("description", "text"); |
2206 | + description.add_attribute_mapping("text", "description"); |
2207 | + widgets.emplace_back(description); |
2208 | + |
2209 | + if (client_.authenticated()) { |
2210 | + ids.emplace_back("comment-inputid"); |
2211 | + sc::PreviewWidget w_commentInput(ids.at(ids.size() - 1), "comment-input"); |
2212 | + w_commentInput.add_attribute_value("submit-label", sc::Variant(_("Post"))); |
2213 | + widgets.emplace_back(w_commentInput); |
2214 | + } |
2215 | + |
2216 | + sc::VariantBuilder builder; |
2217 | + sc::PreviewWidget actions("actions", "actions"); |
2218 | + { |
2219 | + string purchase_url = res["purchase-url"].get_string(); |
2220 | + if (!purchase_url.empty()) { |
2221 | + builder.add_tuple({ |
2222 | + {"id", sc::Variant("buy")}, |
2223 | + {"label", sc::Variant(_("Buy"))}, |
2224 | + {"uri", sc::Variant(purchase_url)} |
2225 | + }); |
2226 | + } |
2227 | + string video_url = res["video-url"].get_string(); |
2228 | + if (!video_url.empty()) { |
2229 | + builder.add_tuple({ |
2230 | + {"id", sc::Variant("video")}, |
2231 | + {"label", sc::Variant(_("Watch video"))}, |
2232 | + {"uri", sc::Variant(video_url)} |
2233 | + }); |
2234 | + } |
2235 | + { |
2236 | + builder.add_tuple({ |
2237 | + {"id", sc::Variant("play")}, |
2238 | + {"label", sc::Variant(_("Play in browser"))} |
2239 | + }); |
2240 | + } |
2241 | + if (client_.authenticated()) { |
2242 | + sc::CannedQuery new_query(SCOPE_NAME); |
2243 | + new_query.set_department_id("userid:" + userid); |
2244 | + builder.add_tuple({ |
2245 | + {"id", sc::Variant("usertracks")}, |
2246 | + {"label", sc::Variant(_("Get user tracks"))}, |
2247 | + {"uri", sc::Variant(new_query.to_uri())} |
2248 | + }); |
2249 | + |
2250 | + future<bool> like_future = client_.is_fav_track(trackid); |
2251 | + auto status = get_or_throw(like_future); |
2252 | + cout << "is fav stats: " << status << endl; |
2253 | + if (status == true) { |
2254 | + builder.add_tuple({ |
2255 | + {"id", sc::Variant("deletelike")}, |
2256 | + {"label", sc::Variant(_("Remove 'Like'"))} |
2257 | + }); |
2258 | + } else { |
2259 | + builder.add_tuple({ |
2260 | + {"id", sc::Variant("like")}, |
2261 | + {"label", sc::Variant(_("Like"))} |
2262 | + }); |
2263 | + } |
2264 | + |
2265 | + future<bool> follow_future = client_.is_user_follower(userid); |
2266 | + status = get_or_throw(follow_future); |
2267 | + cout << "is users follower: " << status << endl; |
2268 | + if (status == true) { |
2269 | + builder.add_tuple({ |
2270 | + {"id", sc::Variant("unfollow")}, |
2271 | + {"label", sc::Variant(_("Unfollow"))} |
2272 | + }); |
2273 | + } else { |
2274 | + builder.add_tuple({ |
2275 | + {"id", sc::Variant("follow")}, |
2276 | + {"label", sc::Variant(_("Follow"))} |
2277 | + }); |
2278 | + } |
2279 | + } |
2280 | + } |
2281 | + actions.add_attribute_value("actions", builder.end()); |
2282 | + widgets.emplace_back(actions); |
2283 | + |
2284 | + future<deque<Comment>> comment_future; |
2285 | + comment_future = client_.track_comments(trackid); |
2286 | + |
2287 | + int index = 0; |
2288 | + for (const auto &comment : get_or_throw(comment_future)) { |
2289 | + std::string id = "commentId_"+ std::to_string(index++); |
2290 | + ids.emplace_back(id); |
2291 | + |
2292 | + sc::PreviewWidget w_comment(id, "comment"); |
2293 | + w_comment.add_attribute_value("comment", sc::Variant(comment.body())); |
2294 | + w_comment.add_attribute_value("author", sc::Variant(comment.title())); |
2295 | + w_comment.add_attribute_value("source", sc::Variant(comment.artwork())); |
2296 | + w_comment.add_attribute_value("subtitle", sc::Variant(comment.created_at())); |
2297 | + widgets.emplace_back(w_comment); |
2298 | + } |
2299 | + } |
2300 | + |
2301 | + layout1col.add_column(ids); |
2302 | + reply->register_layout( { layout1col }); //, layout2col, layout3col |
2303 | + reply->push(widgets); |
2304 | + }catch (domain_error &e) { |
2305 | + cerr << e.what() << endl; |
2306 | + reply->error(current_exception()); |
2307 | + } |
2308 | } |
2309 | |
2310 | === modified file 'src/scope/query.cpp' |
2311 | --- src/scope/query.cpp 2014-12-04 13:39:07 +0000 |
2312 | +++ src/scope/query.cpp 2016-02-02 11:41:52 +0000 |
2313 | @@ -14,8 +14,10 @@ |
2314 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2315 | * |
2316 | * Author: Pete Woods <pete.woods@canonical.com> |
2317 | + * Gary Wang <gary.wang@canonical.com> |
2318 | */ |
2319 | |
2320 | +#include <boost/algorithm/string/predicate.hpp> |
2321 | #include <boost/algorithm/string/trim.hpp> |
2322 | |
2323 | #include <scope/localization.h> |
2324 | @@ -74,19 +76,53 @@ |
2325 | { |
2326 | "schema-version": 1, |
2327 | "template": { |
2328 | - "category-layout": "grid", |
2329 | - "card-size": "large", |
2330 | - "card-background": "color:///#ff4200" |
2331 | + "category-layout": "vertical-journal", |
2332 | + "card-size": "large", |
2333 | + "card-background": "color:///#ff5500" |
2334 | + }, |
2335 | + "components": { |
2336 | + "title": "title" |
2337 | + } |
2338 | +} |
2339 | +)"; |
2340 | + |
2341 | +const static string SHOW_EMPTY_TRACK_TIPS = R"( |
2342 | +{ |
2343 | + "schema-version": 1, |
2344 | + "template": { |
2345 | + "category-layout": "grid", |
2346 | + "card-size": "large", |
2347 | + "card-layout": "horizontal" |
2348 | + }, |
2349 | + "components": { |
2350 | + "title": "title" |
2351 | + } |
2352 | +} |
2353 | +)"; |
2354 | + |
2355 | +const static string USER_INFO_TEMPLATE = R"( |
2356 | +{ |
2357 | + "schema-version": 1, |
2358 | + "template": { |
2359 | + "category-layout": "grid", |
2360 | + "card-background": "color:///#FFFFFF", |
2361 | + "card-size": "medium", |
2362 | + "card-layout": "horizontal" |
2363 | }, |
2364 | "components": { |
2365 | "title": "title", |
2366 | - "background": "background", |
2367 | "art" : { |
2368 | - "aspect-ratio": 100.0 |
2369 | + "field": "art" |
2370 | + }, |
2371 | + "subtitle": "subtitle", |
2372 | + "attributes": { |
2373 | + "field": "attributes", |
2374 | + "max-count": 3 |
2375 | } |
2376 | } |
2377 | } |
2378 | )"; |
2379 | + |
2380 | // unconfuse emacs: " |
2381 | |
2382 | static const vector<string> AUDIO_DEPARTMENT_IDS { "Audiobooks", "Business", |
2383 | @@ -127,9 +163,15 @@ |
2384 | return f.get(); |
2385 | } |
2386 | |
2387 | -static sc::Department::SPtr create_departments(const sc::CannedQuery &query) { |
2388 | +static sc::Department::SPtr create_departments(const sc::CannedQuery &query, |
2389 | + bool contains_fav) { |
2390 | sc::Department::SPtr root_department = sc::Department::create("", query, |
2391 | MUSIC_DEPARTMENT_NAMES.front()); |
2392 | + if (contains_fav) { |
2393 | + sc::Department::SPtr dept = sc::Department::create( |
2394 | + "my_fav", query, _("My favorites")); |
2395 | + root_department->add_subdepartment(dept); |
2396 | + } |
2397 | for (size_t i = 1; i < MUSIC_DEPARTMENT_IDS.size(); ++i) { |
2398 | sc::Department::SPtr dept = sc::Department::create( |
2399 | MUSIC_DEPARTMENT_IDS[i], query, MUSIC_DEPARTMENT_NAMES[i]); |
2400 | @@ -195,21 +237,40 @@ |
2401 | try { |
2402 | const sc::CannedQuery &query(sc::SearchQueryBase::query()); |
2403 | string query_string = alg::trim_copy(query.query_string()); |
2404 | - |
2405 | - reply->register_departments(create_departments(query)); |
2406 | + string department_id = query.department_id(); |
2407 | + |
2408 | + bool authenticated = client_.authenticated(); |
2409 | + sc::Department::SPtr root_depts = create_departments(query, authenticated); |
2410 | + |
2411 | + bool is_dummy_depts = alg::starts_with(department_id, "userid:"); |
2412 | + if (is_dummy_depts) { |
2413 | + sc::Department::SPtr dummy = sc::Department::create( |
2414 | + department_id, query, " "); |
2415 | + root_depts->add_subdepartment(dummy); |
2416 | + } |
2417 | + |
2418 | + reply->register_departments(root_depts); |
2419 | |
2420 | // Avoid blocking on HTTP requests at this point |
2421 | |
2422 | sc::Category::SCPtr first_cat; |
2423 | + sc::Category::SCPtr user_cat; |
2424 | future<deque<Track>> stream_future; |
2425 | + future<User> user_future; |
2426 | bool reading_stream = false; |
2427 | - if (query_string.empty() && query.department_id().empty()) { |
2428 | - if (client_.authenticated()) { |
2429 | + bool reading_user_info = false; |
2430 | + if (query_string.empty() && department_id.empty()) { |
2431 | + if (authenticated) { |
2432 | + user_cat = reply->register_category("user", "", "", |
2433 | + sc::CategoryRenderer(USER_INFO_TEMPLATE)); |
2434 | + user_future = client_.get_authuser_info(); |
2435 | + |
2436 | first_cat = reply->register_category( |
2437 | "stream", _("Stream"), "", |
2438 | sc::CategoryRenderer(SEARCH_CATEGORY_TEMPLATE)); |
2439 | stream_future = client_.stream_tracks(30); |
2440 | reading_stream = true; |
2441 | + reading_user_info = true; |
2442 | } else { |
2443 | add_login_nag(reply); |
2444 | } |
2445 | @@ -220,22 +281,42 @@ |
2446 | if (query_string.empty()) { |
2447 | second_cat = reply->register_category("explore", _("Explore"), "", |
2448 | sc::CategoryRenderer(SEARCH_CATEGORY_TEMPLATE)); |
2449 | - tracks_future = client_.search_tracks({ |
2450 | - { SP::query, query_string }, |
2451 | - { SP::limit, "15" }, |
2452 | - { SP::genre, department_to_category(query.department_id()) }, |
2453 | - { SP::order, "hotness" } |
2454 | - }); |
2455 | + if (department_id == "my_fav") { |
2456 | + tracks_future = client_.favorite_tracks(); |
2457 | + } else if (is_dummy_depts) { |
2458 | + //create dummy department to pass the validation check |
2459 | + user_cat = reply->register_category("user", "", "", |
2460 | + sc::CategoryRenderer(USER_INFO_TEMPLATE)); |
2461 | + |
2462 | + string userId = department_id.substr(department_id.find(':') + 1); |
2463 | + user_future = client_.get_user_info(userId); |
2464 | + tracks_future = client_.get_user_tracks(userId, 15); |
2465 | + reading_user_info = true; |
2466 | + } else { |
2467 | + tracks_future = client_.search_tracks({ |
2468 | + { SP::query, query_string }, |
2469 | + { SP::limit, "15" }, |
2470 | + { SP::genre, department_to_category(department_id) }, |
2471 | + { SP::order, "hotness" } |
2472 | + }); |
2473 | + } |
2474 | } else { |
2475 | second_cat = reply->register_category("search", "", "", |
2476 | sc::CategoryRenderer(SEARCH_CATEGORY_TEMPLATE)); |
2477 | + |
2478 | tracks_future = client_.search_tracks( { |
2479 | - { SP::query, query_string }, |
2480 | - { SP::limit, "30" } |
2481 | + { SP::query, query_string }, |
2482 | + { SP::limit, "30" } |
2483 | }); |
2484 | } |
2485 | |
2486 | // Now we come to wait for the results |
2487 | + if (reading_user_info) { |
2488 | + User user = get_or_throw(user_future); |
2489 | + if (!push_user_info(reply, user_cat, user)) { |
2490 | + return; |
2491 | + } |
2492 | + } |
2493 | |
2494 | if (reading_stream) { |
2495 | for (const auto &track : get_or_throw(stream_future)) { |
2496 | @@ -245,12 +326,19 @@ |
2497 | } |
2498 | } |
2499 | |
2500 | - for (const auto &track : get_or_throw(tracks_future)) { |
2501 | + deque<Track> tracklist = get_or_throw(tracks_future); |
2502 | + for (const auto &track : tracklist) { |
2503 | if (!push_track(reply, second_cat, track)) { |
2504 | return; |
2505 | } |
2506 | } |
2507 | |
2508 | + if (tracklist.size() == 0) { |
2509 | + if (!show_empty_tip(reply)) { |
2510 | + return; |
2511 | + } |
2512 | + } |
2513 | + |
2514 | } catch (domain_error &e) { |
2515 | cerr << e.what() << endl; |
2516 | reply->error(current_exception()); |
2517 | @@ -269,7 +357,8 @@ |
2518 | } else { |
2519 | res.set_art(track.user().artwork()); |
2520 | } |
2521 | - |
2522 | + |
2523 | + res["id"] = std::to_string(track.id()); |
2524 | res["label"] = track.label_name(); |
2525 | res["streamable"] = track.streamable(); |
2526 | res["stream-url"] = track.stream_url() + "?client_id=" + client_.client_id(); |
2527 | @@ -277,20 +366,89 @@ |
2528 | res["video-url"] = track.video_url(); |
2529 | res["waveform"] = track.waveform(); |
2530 | res["username"] = track.user().title(); |
2531 | + res["userid"] = std::to_string(track.user().id()); |
2532 | res["description"] = track.description(); |
2533 | |
2534 | string duration = format_time(track.duration()); |
2535 | string playback_count = u8"\u25B6 " + format_fixed(track.playback_count()); |
2536 | - string favoritings_count = u8"\u2665 " + format_fixed(track.favoritings_count()); |
2537 | + string favoritings_count = u8"\u263B " + format_fixed(track.favoritings_count()); |
2538 | + string likes_count = u8"\u2665 " + format_fixed(track.likes_count()); |
2539 | + string repost_count = u8"\u2B94 " + format_fixed(track.repost_count()); |
2540 | + string comment_count = u8"\u270E " + format_fixed(track.comment_count()); |
2541 | res["duration"] = (int) (track.duration() / 1000); |
2542 | res["playback-count"] = playback_count; |
2543 | res["favoritings-count"] = favoritings_count; |
2544 | + res["likes-count"] = likes_count; |
2545 | + res["repost-count"] = repost_count; |
2546 | + res["comment-count"] = comment_count; |
2547 | + |
2548 | + sc::VariantArray trackinfo { |
2549 | + sc::Variant(sc::VariantArray{sc::Variant(_("create time")), sc::Variant(track.created_at())}), |
2550 | + sc::Variant(sc::VariantArray{sc::Variant(_("genre")), sc::Variant(track.genre())}), |
2551 | + sc::Variant(sc::VariantArray{sc::Variant(_("license")), sc::Variant(track.license())}) |
2552 | + }; |
2553 | + res["trackinfo"] = sc::Variant(trackinfo); |
2554 | |
2555 | sc::VariantBuilder builder; |
2556 | builder.add_tuple({{"value", sc::Variant(duration)}}); |
2557 | builder.add_tuple({{"value", sc::Variant(playback_count)}}); |
2558 | - builder.add_tuple({{"value", sc::Variant(favoritings_count)}}); |
2559 | - res["attributes"] = builder.end(); |
2560 | + |
2561 | + //favorite api doesn't contains likes_count field when retrieving auth user favorites list |
2562 | + //activity api doesn't contains favoritings_count field when retrieving stream list |
2563 | + if (track.likes_count() > 0) |
2564 | + builder.add_tuple({{"value", sc::Variant(likes_count)}}); |
2565 | + else |
2566 | + builder.add_tuple({{"value", sc::Variant(favoritings_count)}}); |
2567 | + |
2568 | + res["attributes"] = builder.end(); |
2569 | + |
2570 | + res["mode"] = _("track"); |
2571 | + |
2572 | + return reply->push(res); |
2573 | +} |
2574 | + |
2575 | +bool Query::push_user_info(const sc::SearchReplyProxy &reply, |
2576 | + const sc::Category::SCPtr &category, |
2577 | + const User &user) { |
2578 | + |
2579 | + sc::CategorisedResult res(category); |
2580 | + |
2581 | + res.set_uri(user.permalink_url()); |
2582 | + res.set_title(user.title()); |
2583 | + res.set_art(user.artwork()); |
2584 | + res["subtitle"] = user.permalink_url() + " "+ user.bio(); |
2585 | + |
2586 | + string track_count = "<b> "+ format_fixed(user.track_count()) + _("</b> tracks"); |
2587 | + string followers_count = "<b> "+ format_fixed(user.followers_count()) + _("</b> followers"); |
2588 | + string followings_count = "<b> "+ format_fixed(user.followings_count()) + _("</b> followings"); |
2589 | + res["track-count"] = track_count; |
2590 | + res["followers-count"] = followers_count; |
2591 | + res["followings-count"] = followings_count; |
2592 | + res["permalink-url"] = user.permalink_url(); |
2593 | + res["bio"] = user.bio(); |
2594 | + res["id"] = std::to_string(user.id()); |
2595 | + |
2596 | + sc::VariantBuilder builder; |
2597 | + builder.add_tuple({{"value", sc::Variant(track_count)}}); |
2598 | + builder.add_tuple({{"value", sc::Variant(followers_count)}}); |
2599 | + builder.add_tuple({{"value", sc::Variant(followings_count)}}); |
2600 | + |
2601 | + res["attributes"] = builder.end(); |
2602 | + res["mode"] = _("user"); |
2603 | + |
2604 | + return reply->push(res); |
2605 | +} |
2606 | + |
2607 | +bool Query::show_empty_tip(const unity::scopes::SearchReplyProxy &reply) |
2608 | +{ |
2609 | + //Stay on surface and avoid user to enter card view if no tracks are found |
2610 | + const sc::CannedQuery &query(sc::SearchQueryBase::query()); |
2611 | + sc::CategoryRenderer rdr(SHOW_EMPTY_TRACK_TIPS); |
2612 | + auto cat = reply->register_category("show_empty_tips", "", "", rdr); |
2613 | + |
2614 | + sc::CategorisedResult res(cat); |
2615 | + res.set_uri(query.to_uri()); |
2616 | + res.set_title(_("No tracks can be found")); |
2617 | |
2618 | return reply->push(res); |
2619 | } |
2620 | |
2621 | === modified file 'src/scope/scope.cpp' |
2622 | --- src/scope/scope.cpp 2014-12-04 13:39:07 +0000 |
2623 | +++ src/scope/scope.cpp 2016-02-02 11:41:52 +0000 |
2624 | @@ -14,12 +14,14 @@ |
2625 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2626 | * |
2627 | * Author: Pete Woods <pete.woods@canonical.com> |
2628 | + * Gary Wang <gary.wang@canonical.com> |
2629 | */ |
2630 | |
2631 | #include <scope/localization.h> |
2632 | #include <scope/preview.h> |
2633 | #include <scope/query.h> |
2634 | #include <scope/scope.h> |
2635 | +#include <scope/activation.h> |
2636 | |
2637 | namespace sc = unity::scopes; |
2638 | using namespace std; |
2639 | @@ -48,7 +50,14 @@ |
2640 | |
2641 | sc::PreviewQueryBase::UPtr Scope::preview(sc::Result const& result, |
2642 | sc::ActionMetadata const& metadata) { |
2643 | - return sc::PreviewQueryBase::UPtr(new Preview(result, metadata)); |
2644 | + return sc::PreviewQueryBase::UPtr(new Preview(result, metadata, oa_client_)); |
2645 | +} |
2646 | + |
2647 | +sc::ActivationQueryBase::UPtr Scope::perform_action(const sc::Result &result, |
2648 | + const sc::ActionMetadata &metadata, |
2649 | + const std::string &widget_id, |
2650 | + const std::string &action_id) { |
2651 | + return sc::ActivationQueryBase::UPtr(new Activation(result, metadata, action_id, oa_client_)); |
2652 | } |
2653 | |
2654 | #define EXPORT __attribute__ ((visibility ("default"))) |