Merge lp:~miwaxe+launchpad/synapse-project/clementine-support into lp:synapse-project

Proposed by Andrea Brancaleoni
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
Reviewer Review Type Date Requested Status
Jeremy Munsch (community) Needs Resubmitting
Michal Hruby Needs Information
Review via email: mp+195676@code.launchpad.net

Description of the change

I've ported the XNoise plugin to Clementine, my favourite music player. Please review it!

:-)

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

Code-wise this looks perfectly fine, but could use testing from someone who uses clementine... Any takers?

review: Needs Information
Revision history for this message
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.

Revision history for this message
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.

review: Needs Resubmitting
Revision history for this message
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

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