Merge lp:~miwaxe+launchpad/synapse-project/clementine-support into lp:synapse-project
- clementine-support
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~miwaxe+launchpad/synapse-project/clementine-support |
Merge into: | lp:synapse-project |
Diff against target: |
497 lines (+471/-0) 3 files modified
src/plugins/Makefile.am (+1/-0) src/plugins/clementine-plugin.vala (+469/-0) src/ui/synapse-main.vala (+1/-0) |
To merge this branch: | bzr merge lp:~miwaxe+launchpad/synapse-project/clementine-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeremy Munsch (community) | Needs Resubmitting | ||
Michal Hruby | Needs Information | ||
Review via email: mp+195676@code.launchpad.net |
Commit message
Description of the change
I've ported the XNoise plugin to Clementine, my favourite music player. Please review it!
:-)
Jeremy Munsch (jeremy-munsch) wrote : | # |
I just wanted to try this on 15.04 but a dependency is unique-3.0 which is not available anymore.
looks like gir1.2-unique-3.0 was last available in Saucy (13.10).
Since last LTS is Trusty (14.04), this should be update with the last version of synapse in order to be tested.
Jeremy Munsch (jeremy-munsch) wrote : | # |
> I just wanted to try this on 15.04 but a dependency is unique-3.0 which is not
> available anymore.
> looks like gir1.2-unique-3.0 was last available in Saucy (13.10).
>
> Since last LTS is Trusty (14.04), this should be update with the last version
> of synapse in order to be tested.
I also tested the code in the last version of synapse, but the code is outdated right now. So it needs a great update to be used.
Jeremy Munsch (jeremy-munsch) wrote : | # |
Oups sorry i miss clicked for the resubmit.
Unmerged revisions
- 514. By Andrea Brancaleoni <email address hidden>
-
Clementine Plugin
Preview Diff
1 | === modified file 'src/plugins/Makefile.am' |
2 | --- src/plugins/Makefile.am 2013-07-02 23:06:40 +0000 |
3 | +++ src/plugins/Makefile.am 2013-11-18 21:23:46 +0000 |
4 | @@ -52,6 +52,7 @@ |
5 | selection-plugin.vala \ |
6 | test-slow-plugin.vala \ |
7 | xnoise-media-player-plugin.vala \ |
8 | + clementine-plugin.vala \ |
9 | system-management.vala \ |
10 | $(NULL) |
11 | |
12 | |
13 | === added file 'src/plugins/clementine-plugin.vala' |
14 | --- src/plugins/clementine-plugin.vala 1970-01-01 00:00:00 +0000 |
15 | +++ src/plugins/clementine-plugin.vala 2013-11-18 21:23:46 +0000 |
16 | @@ -0,0 +1,469 @@ |
17 | +/* |
18 | + * Copyright (C) 2012 Jörn Magens <shuerhaaken@googlemail.com> |
19 | + * |
20 | + * This program is free software; you can redistribute it and/or modify |
21 | + * it under the terms of the GNU General Public License as published by |
22 | + * the Free Software Foundation; either version 2 of the License, or |
23 | + * (at your option) any later version. |
24 | + * |
25 | + * This program is distributed in the hope that it will be useful, |
26 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
28 | + * GNU General Public License for more details. |
29 | + * |
30 | + * You should have received a copy of the GNU General Public License |
31 | + * along with this program; if not, write to the Free Software |
32 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
33 | + * |
34 | + * Authored by Jörn Magens <shuerhaaken@googlemail.com> |
35 | + * Authored by Andrea Brancaleoni <miwaxe@gmail.com> |
36 | + * |
37 | + */ |
38 | + |
39 | +namespace Synapse |
40 | +{ |
41 | + [DBus (name = "org.mpris.MediaPlayer2.Player")] |
42 | + private interface ClementinePlayer : Object |
43 | + { |
44 | + public const string UNIQUE_NAME = "org.mpris.MediaPlayer2.clementine"; |
45 | + public const string OBJECT_PATH = "/org/mpris/MediaPlayer2"; |
46 | + |
47 | + public abstract void next () throws IOError; |
48 | + public abstract void previous () throws IOError; |
49 | + public abstract void pause () throws IOError; |
50 | + public abstract void play_pause () throws IOError; |
51 | + public abstract void stop () throws IOError; |
52 | + public abstract void play () throws IOError; |
53 | + public abstract void open_uri (string uri) throws IOError; |
54 | + } |
55 | + |
56 | + [DBus (name = "org.mpris.MediaPlayer2")] |
57 | + private interface ClementineEngine : Object |
58 | + { |
59 | + public const string UNIQUE_NAME = "org.mpris.MediaPlayer2.clementine"; |
60 | + public const string OBJECT_PATH = "/org/mpris/MediaPlayer2"; |
61 | + |
62 | + public abstract void quit () throws IOError; |
63 | + public abstract void raise () throws IOError; |
64 | + } |
65 | + |
66 | + public class ClementineActions: Object, Activatable, ItemProvider, ActionProvider |
67 | + { |
68 | + public bool enabled { get; set; default = true; } |
69 | + |
70 | + public void activate () |
71 | + { |
72 | + } |
73 | + |
74 | + public void deactivate () |
75 | + { |
76 | + } |
77 | + |
78 | + static void register_plugin () |
79 | + { |
80 | + DataSink.PluginRegistry.get_default ().register_plugin ( |
81 | + typeof (ClementineActions), |
82 | + "Clementine", |
83 | + _ ("Control Clementine media player."), |
84 | + "clementine", |
85 | + register_plugin, |
86 | + Environment.find_program_in_path ("clementine") != null, |
87 | + _ ("Clementine is not installed!") |
88 | + ); |
89 | + } |
90 | + |
91 | + static construct |
92 | + { |
93 | + register_plugin (); |
94 | + } |
95 | + |
96 | + private abstract class ClementineAction: Object, Match |
97 | + { |
98 | + // from Match interface |
99 | + public string title { get; construct set; } |
100 | + public string description { get; set; } |
101 | + public string icon_name { get; construct set; } |
102 | + public bool has_thumbnail { get; construct set; } |
103 | + public string thumbnail_path { get; construct set; } |
104 | + public MatchType match_type { get; construct set; } |
105 | + public int default_relevancy { get; set; } |
106 | + |
107 | + public abstract bool valid_for_match (Match match); |
108 | + public abstract void execute_internal (Match? match); |
109 | + |
110 | + public void execute (Match? match) |
111 | + { |
112 | + execute_internal (match); |
113 | + } |
114 | + |
115 | + public virtual int get_relevancy () |
116 | + { |
117 | + bool clementine_running = DBusService.get_default ().name_has_owner ( |
118 | + ClementinePlayer.UNIQUE_NAME); |
119 | + return clementine_running ? default_relevancy + Match.Score.INCREMENT_LARGE : default_relevancy; |
120 | + } |
121 | + } |
122 | + |
123 | + private abstract class ClementineControlMatch: Object, Match |
124 | + { |
125 | + // for Match interface |
126 | + public string title { get; construct set; } |
127 | + public string description { get; set; default = ""; } |
128 | + public string icon_name { get; construct set; default = ""; } |
129 | + public bool has_thumbnail { get; construct set; default = false; } |
130 | + public string thumbnail_path { get; construct set; } |
131 | + public MatchType match_type { get; construct set; } |
132 | + |
133 | + public void execute (Match? match) |
134 | + { |
135 | + this.do_action (); |
136 | + } |
137 | + |
138 | + public abstract void do_action (); |
139 | + |
140 | + public virtual bool action_available () |
141 | + { |
142 | + return DBusService.get_default ().name_has_owner ( |
143 | + ClementinePlayer.UNIQUE_NAME |
144 | + ); |
145 | + } |
146 | + } |
147 | + |
148 | + /* MATCHES of Type.ACTION */ |
149 | + private class Quit : ClementineControlMatch |
150 | + { |
151 | + public Quit () |
152 | + { |
153 | + Object (title: _ ("Quit"), |
154 | + description: _ ("Quit Clementine"), |
155 | + icon_name: "gtk-close", |
156 | + has_thumbnail: false, |
157 | + match_type: MatchType.ACTION |
158 | + ); |
159 | + } |
160 | + |
161 | + public override void do_action () |
162 | + { |
163 | + try { |
164 | + ClementineEngine player = Bus.get_proxy_sync (BusType.SESSION, |
165 | + ClementineEngine.UNIQUE_NAME, |
166 | + ClementineEngine.OBJECT_PATH); |
167 | + player.quit (); |
168 | + } catch (IOError e) { |
169 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
170 | + } |
171 | + } |
172 | + } |
173 | + |
174 | + private class Raise : ClementineControlMatch |
175 | + { |
176 | + public Raise () |
177 | + { |
178 | + Object (title: _ ("Raise"), |
179 | + description: _ ("Show Clementine"), |
180 | + icon_name: "clementine", |
181 | + has_thumbnail: false, |
182 | + match_type: MatchType.ACTION |
183 | + ); |
184 | + } |
185 | + |
186 | + public override void do_action () |
187 | + { |
188 | + try { |
189 | + ClementineEngine player = Bus.get_proxy_sync (BusType.SESSION, |
190 | + ClementineEngine.UNIQUE_NAME, |
191 | + ClementineEngine.OBJECT_PATH); |
192 | + player.raise (); |
193 | + } catch (IOError e) { |
194 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
195 | + } |
196 | + } |
197 | + } |
198 | + |
199 | + private class Play : ClementineControlMatch |
200 | + { |
201 | + public Play () |
202 | + { |
203 | + Object (title: _ ("Play"), |
204 | + description: _ ("Start playback in Clementine"), |
205 | + icon_name: "media-playback-start", |
206 | + has_thumbnail: false, |
207 | + match_type: MatchType.ACTION |
208 | + ); |
209 | + } |
210 | + |
211 | + public override void do_action () |
212 | + { |
213 | + try { |
214 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
215 | + ClementinePlayer.UNIQUE_NAME, |
216 | + ClementinePlayer.OBJECT_PATH); |
217 | + player.play (); |
218 | + } catch (IOError e) { |
219 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
220 | + } |
221 | + } |
222 | + } |
223 | + |
224 | + private class TogglePlaying : ClementineControlMatch |
225 | + { |
226 | + public TogglePlaying () |
227 | + { |
228 | + Object (title: _ ("TogglePlaying"), |
229 | + description: _ ("Start/Pause playback in Clementine"), |
230 | + icon_name: "media-playback-pause", |
231 | + has_thumbnail: false, |
232 | + match_type: MatchType.ACTION |
233 | + ); |
234 | + } |
235 | + |
236 | + public override void do_action () |
237 | + { |
238 | + try { |
239 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
240 | + ClementinePlayer.UNIQUE_NAME, |
241 | + ClementinePlayer.OBJECT_PATH); |
242 | + player.play_pause (); |
243 | + } catch (IOError e) { |
244 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
245 | + } |
246 | + } |
247 | + |
248 | + public override bool action_available () |
249 | + { |
250 | + return true; |
251 | + } |
252 | + } |
253 | + |
254 | + private class Pause : ClementineControlMatch |
255 | + { |
256 | + public Pause () |
257 | + { |
258 | + Object (title: _ ("Pause"), |
259 | + description: _ ("Pause playback in Clementine"), |
260 | + icon_name: "media-playback-pause", |
261 | + has_thumbnail: false, |
262 | + match_type: MatchType.ACTION |
263 | + ); |
264 | + } |
265 | + |
266 | + public override void do_action () |
267 | + { |
268 | + try { |
269 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
270 | + ClementinePlayer.UNIQUE_NAME, |
271 | + ClementinePlayer.OBJECT_PATH); |
272 | + player.pause (); |
273 | + } catch (IOError e) { |
274 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
275 | + } |
276 | + } |
277 | + } |
278 | + |
279 | + private class Next : ClementineControlMatch |
280 | + { |
281 | + public Next () |
282 | + { |
283 | + Object (title: _ ("Next"), |
284 | + description: _ ("Plays the next song in Clementine's playlist"), |
285 | + icon_name: "media-skip-forward", |
286 | + has_thumbnail: false, |
287 | + match_type: MatchType.ACTION |
288 | + ); |
289 | + } |
290 | + |
291 | + public override void do_action () |
292 | + { |
293 | + try { |
294 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
295 | + ClementinePlayer.UNIQUE_NAME, |
296 | + ClementinePlayer.OBJECT_PATH); |
297 | + |
298 | + player.next (); |
299 | + } catch (IOError e) { |
300 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
301 | + } |
302 | + } |
303 | + } |
304 | + |
305 | + private class Previous : ClementineControlMatch |
306 | + { |
307 | + public Previous () |
308 | + { |
309 | + Object (title: _ ("Previous"), |
310 | + description: _ ("Plays the previous song in Clementine's playlist"), |
311 | + icon_name: "media-skip-backward", |
312 | + has_thumbnail: false, |
313 | + match_type: MatchType.ACTION |
314 | + ); |
315 | + } |
316 | + |
317 | + public override void do_action () |
318 | + { |
319 | + try { |
320 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
321 | + ClementinePlayer.UNIQUE_NAME, |
322 | + ClementinePlayer.OBJECT_PATH); |
323 | + player.previous (); |
324 | + } catch (IOError e) { |
325 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
326 | + } |
327 | + } |
328 | + } |
329 | + |
330 | + private class Stop : ClementineControlMatch |
331 | + { |
332 | + public Stop () |
333 | + { |
334 | + Object (title: _ ("Stop"), |
335 | + description: _ ("Stops the playback of Clementine"), |
336 | + icon_name: "media-playback-stop", |
337 | + has_thumbnail: false, |
338 | + match_type: MatchType.ACTION |
339 | + ); |
340 | + } |
341 | + |
342 | + public override void do_action () |
343 | + { |
344 | + try { |
345 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
346 | + ClementinePlayer.UNIQUE_NAME, |
347 | + ClementinePlayer.OBJECT_PATH); |
348 | + player.stop (); |
349 | + } catch (IOError e) { |
350 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
351 | + } |
352 | + } |
353 | + } |
354 | + |
355 | + /* ACTIONS FOR MP3s */ |
356 | + private class OpenUri: ClementineAction |
357 | + { |
358 | + public OpenUri () |
359 | + { |
360 | + Object (title: _ ("Play in Clementine"), |
361 | + description: _ ("Queues and plays the song"), |
362 | + icon_name: "media-playback-start", |
363 | + has_thumbnail: false, |
364 | + match_type: MatchType.ACTION, |
365 | + default_relevancy: Match.Score.ABOVE_AVERAGE |
366 | + ); |
367 | + } |
368 | + |
369 | + public override void execute_internal (Match? match) |
370 | + { |
371 | + return_if_fail (match.match_type == MatchType.GENERIC_URI); |
372 | + UriMatch uri = match as UriMatch; |
373 | + return_if_fail ((uri.file_type & QueryFlags.AUDIO) != 0 || |
374 | + (uri.file_type & QueryFlags.VIDEO) != 0); |
375 | + try { |
376 | + ClementinePlayer player = Bus.get_proxy_sync (BusType.SESSION, |
377 | + ClementinePlayer.UNIQUE_NAME, |
378 | + ClementinePlayer.OBJECT_PATH); |
379 | + player.open_uri (uri.uri); |
380 | + player.play (); |
381 | + } catch (IOError e) { |
382 | + Utils.Logger.warning (this, "Clementine is not available.\n%s", e.message); |
383 | + } |
384 | + } |
385 | + |
386 | + public override bool valid_for_match (Match match) |
387 | + { |
388 | + switch (match.match_type) |
389 | + { |
390 | + case MatchType.GENERIC_URI: |
391 | + UriMatch uri = match as UriMatch; |
392 | + if ((uri.file_type & QueryFlags.AUDIO) != 0 || |
393 | + (uri.file_type & QueryFlags.VIDEO) != 0) |
394 | + return true; |
395 | + else |
396 | + return false; |
397 | + default: |
398 | + return false; |
399 | + } |
400 | + } |
401 | + } |
402 | + |
403 | + private Gee.List<ClementineAction> actions; |
404 | + private Gee.List<ClementineControlMatch> matches; |
405 | + |
406 | + construct |
407 | + { |
408 | + actions = new Gee.ArrayList<ClementineAction> (); |
409 | + matches = new Gee.ArrayList<ClementineControlMatch> (); |
410 | + |
411 | + actions.add (new OpenUri()); |
412 | + |
413 | + matches.add (new Raise ()); |
414 | + matches.add (new Quit ()); |
415 | + |
416 | + matches.add (new Play ()); |
417 | + matches.add (new TogglePlaying ()); |
418 | + matches.add (new Pause ()); |
419 | + matches.add (new Stop ()); |
420 | + matches.add (new Previous ()); |
421 | + matches.add (new Next ()); |
422 | + } |
423 | + |
424 | + public async ResultSet? search (Query q) throws SearchError |
425 | + { |
426 | + // we only search for actions |
427 | + if (!(QueryFlags.ACTIONS in q.query_type)) return null; |
428 | + |
429 | + var result = new ResultSet (); |
430 | + |
431 | + var matchers = Query.get_matchers_for_query (q.query_string, 0, |
432 | + RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS); |
433 | + |
434 | + foreach (var action in matches) |
435 | + { |
436 | + if (!action.action_available ()) continue; |
437 | + foreach (var matcher in matchers) |
438 | + { |
439 | + if (matcher.key.match (action.title)) |
440 | + { |
441 | + result.add (action, matcher.value - Match.Score.INCREMENT_SMALL); |
442 | + break; |
443 | + } |
444 | + } |
445 | + } |
446 | + q.check_cancellable (); |
447 | + return result; |
448 | + } |
449 | + |
450 | + public ResultSet? find_for_match (ref Query query, Match match) |
451 | + { |
452 | + bool query_empty = query.query_string == ""; |
453 | + var results = new ResultSet (); |
454 | + |
455 | + if (query_empty) |
456 | + { |
457 | + foreach (var action in actions) |
458 | + { |
459 | + if (action.valid_for_match (match)) |
460 | + { |
461 | + results.add (action, action.get_relevancy ()); |
462 | + } |
463 | + } |
464 | + } |
465 | + else |
466 | + { |
467 | + var matchers = Query.get_matchers_for_query (query.query_string, 0, |
468 | + RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS); |
469 | + foreach (var action in actions) |
470 | + { |
471 | + if (!action.valid_for_match (match)) continue; |
472 | + foreach (var matcher in matchers) |
473 | + { |
474 | + if (matcher.key.match (action.title)) |
475 | + { |
476 | + results.add (action, matcher.value); |
477 | + break; |
478 | + } |
479 | + } |
480 | + } |
481 | + } |
482 | + return results; |
483 | + } |
484 | + } |
485 | +} |
486 | |
487 | === modified file 'src/ui/synapse-main.vala' |
488 | --- src/ui/synapse-main.vala 2013-07-20 18:34:34 +0000 |
489 | +++ src/ui/synapse-main.vala 2013-11-18 21:23:46 +0000 |
490 | @@ -177,6 +177,7 @@ |
491 | typeof (SelectionPlugin), |
492 | typeof (SshPlugin), |
493 | typeof (XnoiseActions), |
494 | + typeof (ClementineActions), |
495 | // typeof (FileOpPlugin), |
496 | // typeof (PidginPlugin), |
497 | // typeof (ChatActions), |
Code-wise this looks perfectly fine, but could use testing from someone who uses clementine... Any takers?