Merge lp:~bidossessi-sodonon/synapse-project/mpc-plugin into lp:synapse-project
- mpc-plugin
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~bidossessi-sodonon/synapse-project/mpc-plugin |
Merge into: | lp:synapse-project |
Diff against target: |
667 lines (+641/-0) 3 files modified
src/plugins/Makefile.am (+1/-0) src/plugins/mpc-plugin.vala (+639/-0) src/ui/synapse-main.vala (+1/-0) |
To merge this branch: | bzr merge lp:~bidossessi-sodonon/synapse-project/mpc-plugin |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bidossessi Sodonon (community) | Needs Resubmitting | ||
Alberto Aldegheri | Needs Fixing | ||
Michal Hruby | Needs Fixing | ||
Review via email: mp+62308@code.launchpad.net |
This proposal supersedes a proposal from 2011-05-25.
Commit message
Description of the change
Changed MpcEngine's methods to static to avoid unnecessary instantiation.
Alberto Aldegheri (albyrock87) wrote : Posted in a previous version of this proposal | # |
Bidossessi Sodonon (bidossessi-sodonon) wrote : Posted in a previous version of this proposal | # |
Thanks for your prompt reply.
About 1), blame my lack of programming experience with compiled code. I will update this asap.
Now, for 2), from man mpc:
search <type> <query> [<type> <query>]...
types are: artist, album, title, track, name, genre, date, composer, performer, comment, disc, filename, or any (to match any tag).
Here is a sample of the list returned:
[b_sodonon@sysadmin synapse-project]$ mpc search genre world
Ali Farka Toure & Toumani Diabate/In the Heart of the Moon/02. Kala.mp3
Ali Farka Toure & Toumani Diabate/In the Heart of the Moon/03. Mamadou Boutiquier.mp3
The resulting file paths are relative to mpd's "musid_dir" configuration.
what needs to happen is the following (python):
abs_path = music_dir + rel_path
uri = 'file://' + str(urllib.
I use that code to create uris I feed into zeitgeist.
I have no idea how to do that in vala.
Not to mention that, to enqueue files in mpd, I have to provide relative_path as an argument, which means going from uri to relative path. No idea how I could do that either. So until I become a bit more conversant with vala, I'll stick to the basic functionality.
Once again, thanks for the reply. It feels good be finally giving back to the community. :)
Cheers.
Bidossessi Sodonon (bidossessi-sodonon) wrote : | # |
I hope this is the right way to go about updating my merge proposal.
If not, I'm sorry.
Cheers
Alberto Aldegheri (albyrock87) wrote : | # |
:) Do not resubmit the proposal (I made the same mistake the first time I used Launchpad :P).
Just add a comment an I (or mhr3) will come here and look at changes.
I'll look at your merge proposal asap!
- 443. By Bidossessi Sodonon
-
Forgot to add the "stop" command
- 444. By Bidossessi Sodonon
-
Forgot some strings to make Stop appear
- 445. By Bidossessi Sodonon
-
Fixed unreachable catch issues
- 446. By Bidossessi Sodonon
-
Feature-complete code, as compared to banshee-plugin
Bidossessi Sodonon (bidossessi-sodonon) wrote : | # |
Plugin is now feature-complete, using banshee as a feature basis.
It does the following actions:
- start, stop, pause and resume playback
- enqueue a uri in mpd
- play a track, clearing the playlist
I reinstated instantiation in prevision of Synapse's configuration capabilities.
That way, (almost) no refactoring will be needed.
I'm sure the code is not optimized, but, that's my level, for now.
Cheers
- 447. By Bidossessi Sodonon
-
Fixed the location for this file.
- 448. By Bidossessi Sodonon
-
Updated the pot file.
Michal Hruby (mhr3) wrote : | # |
A few notes:
- please revert the changes to hybrid-
- line 210-217 and others - why do you catch the error, if you only re-throw it?
Other than that it looks ok...
- 449. By Bidossessi Sodonon
-
* reverted hybrid-
search- plugin to previous code
* stopped catching errors in public methods in mpc-plugin (no real need)
* updated synapse.pot to
Bidossessi Sodonon (bidossessi-sodonon) wrote : | # |
> A few notes:
>
> - please revert the changes to hybrid-
> - line 210-217 and others - why do you catch the error, if you only re-throw
> it?
>
> Other than that it looks ok...
Well, I kept catching until vala stopped giving me unhandled error messages. They were kind of scary. But I admint there's no real need to do that.
I believe that with 449, this plugin is ready.
Bidossessi Sodonon (bidossessi-sodonon) wrote : | # |
Please check if more needs to be done for this plugin.
Thank you.
Alberto Aldegheri (albyrock87) wrote : | # |
Please, enter in Synapse's folder, and execute:
bzr revert --revision 440 src/plugins/
And:
bzr revert --revision 440 po/synapse.pot
(we'll update translations later)
At this point: return path[music_
Are you sure that music_root is a prefix of path ?
- 450. By Bidossessi Sodonon
-
Don't try to play files that are not in MPD's music root (since it will fail anyway).
- 451. By Bidossessi Sodonon
-
Reverted pot file and hybrid-
search- plugin to rev 440.
Bidossessi Sodonon (bidossessi-sodonon) wrote : | # |
> Please, enter in Synapse's folder, and execute:
> bzr revert --revision 440 src/plugins/
>
> And:
>
> bzr revert --revision 440 po/synapse.pot
>
> (we'll update translations later)
>
Done, and sorry about that.
> At this point: return path[music_
> diff)
> Are you sure that music_root is a prefix of path ?
Got it: files not in mpd's music_root are now handled.
Unmerged revisions
- 451. By Bidossessi Sodonon
-
Reverted pot file and hybrid-
search- plugin to rev 440. - 450. By Bidossessi Sodonon
-
Don't try to play files that are not in MPD's music root (since it will fail anyway).
- 449. By Bidossessi Sodonon
-
* reverted hybrid-
search- plugin to previous code
* stopped catching errors in public methods in mpc-plugin (no real need)
* updated synapse.pot to - 448. By Bidossessi Sodonon
-
Updated the pot file.
- 447. By Bidossessi Sodonon
-
Fixed the location for this file.
- 446. By Bidossessi Sodonon
-
Feature-complete code, as compared to banshee-plugin
- 445. By Bidossessi Sodonon
-
Fixed unreachable catch issues
- 444. By Bidossessi Sodonon
-
Forgot some strings to make Stop appear
- 443. By Bidossessi Sodonon
-
Forgot to add the "stop" command
- 442. By Bidossessi Sodonon
-
Turned MpcEngine instance method to class methods (static)
Preview Diff
1 | === modified file 'src/plugins/Makefile.am' | |||
2 | --- src/plugins/Makefile.am 2011-04-18 14:49:45 +0000 | |||
3 | +++ src/plugins/Makefile.am 2011-05-31 10:31:30 +0000 | |||
4 | @@ -46,6 +46,7 @@ | |||
5 | 46 | hybrid-search-plugin.vala \ | 46 | hybrid-search-plugin.vala \ |
6 | 47 | launchpad-plugin.vala \ | 47 | launchpad-plugin.vala \ |
7 | 48 | locate-plugin.vala \ | 48 | locate-plugin.vala \ |
8 | 49 | mpc-plugin.vala \ | ||
9 | 49 | opensearch.vala \ | 50 | opensearch.vala \ |
10 | 50 | pastebin-plugin.vala \ | 51 | pastebin-plugin.vala \ |
11 | 51 | pidgin-plugin.vala \ | 52 | pidgin-plugin.vala \ |
12 | 52 | 53 | ||
13 | === added file 'src/plugins/mpc-plugin.vala' | |||
14 | --- src/plugins/mpc-plugin.vala 1970-01-01 00:00:00 +0000 | |||
15 | +++ src/plugins/mpc-plugin.vala 2011-05-31 10:31:30 +0000 | |||
16 | @@ -0,0 +1,639 @@ | |||
17 | 1 | /* | ||
18 | 2 | * Copyright (C) 2011 Bidossessi Sodonon <stanislas.sodonon at gmail.com> | ||
19 | 3 | * | ||
20 | 4 | * This program is free software; you can redistribute it and/or modify | ||
21 | 5 | * it under the terms of the GNU General Public License as published by | ||
22 | 6 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | 7 | * (at your option) any later version. | ||
24 | 8 | * | ||
25 | 9 | * This program is distributed in the hope that it will be useful, | ||
26 | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | 12 | * GNU General Public License for more details. | ||
29 | 13 | * | ||
30 | 14 | * You should have received a copy of the GNU General Public License | ||
31 | 15 | * along with this program; if not, write to the Free Software | ||
32 | 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
33 | 17 | * | ||
34 | 18 | * Authored by Bidossessi Sodonon <stanislas.sodonon at gmail.com> | ||
35 | 19 | * | ||
36 | 20 | */ | ||
37 | 21 | |||
38 | 22 | namespace Synapse | ||
39 | 23 | { | ||
40 | 24 | public class MpcEngine: Object | ||
41 | 25 | { | ||
42 | 26 | // our executable string array | ||
43 | 27 | private const string bin = "mpc"; | ||
44 | 28 | // mpd paths are relative to this directory | ||
45 | 29 | public string music_root {get;construct;} | ||
46 | 30 | // if these default values are given, use them | ||
47 | 31 | public string host {get;construct;} // localhost by defaut | ||
48 | 32 | public string port {get;construct;} // 6600 by default | ||
49 | 33 | public string passwd {get;construct;}// no pasword by default | ||
50 | 34 | |||
51 | 35 | // constructor | ||
52 | 36 | public MpcEngine (string? host = "localhost", | ||
53 | 37 | string? port = "6600", string? passwd = null, | ||
54 | 38 | string? music_root = null) | ||
55 | 39 | { | ||
56 | 40 | // mpc is called like this: mpc [-h [_passwd@]_host] [-p _port] <command> [arguments] | ||
57 | 41 | Object(host: host, port: port, passwd: passwd, music_root: music_root); | ||
58 | 42 | } | ||
59 | 43 | construct { | ||
60 | 44 | //make sure we find the music_dir if it wasn't given. | ||
61 | 45 | music_root = find_music_root(music_root); | ||
62 | 46 | } | ||
63 | 47 | |||
64 | 48 | /* Public operations (pass errors to caller)*/ | ||
65 | 49 | public void stop () throws IOError | ||
66 | 50 | { | ||
67 | 51 | run_command("stop"); | ||
68 | 52 | } | ||
69 | 53 | public void play_pause () throws IOError | ||
70 | 54 | { | ||
71 | 55 | run_command("toggle"); | ||
72 | 56 | } | ||
73 | 57 | public void play_now (string uri) throws IOError | ||
74 | 58 | { | ||
75 | 59 | string rel_path = path_from_uri(uri); | ||
76 | 60 | run_command ("clear"); | ||
77 | 61 | run_command ("add", rel_path); | ||
78 | 62 | run_command ("play"); | ||
79 | 63 | } | ||
80 | 64 | public void enqueue (string uri) throws IOError | ||
81 | 65 | { | ||
82 | 66 | string rel_path = path_from_uri(uri); | ||
83 | 67 | run_command("add", rel_path); | ||
84 | 68 | } | ||
85 | 69 | public void next () throws IOError | ||
86 | 70 | { | ||
87 | 71 | run_command("next"); | ||
88 | 72 | } | ||
89 | 73 | public void previous () throws IOError | ||
90 | 74 | { | ||
91 | 75 | run_command("prev"); | ||
92 | 76 | } | ||
93 | 77 | |||
94 | 78 | /* Engine Internals */ | ||
95 | 79 | // convenience function | ||
96 | 80 | protected string turn_abs(string user_path) | ||
97 | 81 | { | ||
98 | 82 | //this shouldn't affect absolute paths | ||
99 | 83 | try | ||
100 | 84 | { | ||
101 | 85 | MatchInfo info; | ||
102 | 86 | Regex regex = new Regex("^~"); | ||
103 | 87 | string user_dir = Environment.get_home_dir(); | ||
104 | 88 | if (regex.match(user_path, 0, out info)) | ||
105 | 89 | { | ||
106 | 90 | string abs_path = regex.replace (user_path, -1, 0, user_dir); | ||
107 | 91 | //make sure it exists | ||
108 | 92 | var u = File.new_for_path(abs_path); | ||
109 | 93 | if (u.query_exists ()) | ||
110 | 94 | { | ||
111 | 95 | return abs_path; | ||
112 | 96 | } | ||
113 | 97 | } | ||
114 | 98 | } | ||
115 | 99 | // ouch, what happened? | ||
116 | 100 | catch (Error e) | ||
117 | 101 | { | ||
118 | 102 | Utils.Logger.warning (this,"Failed to turn %s to absolute path: %s", user_path, e.message); | ||
119 | 103 | } | ||
120 | 104 | return user_path; | ||
121 | 105 | } | ||
122 | 106 | |||
123 | 107 | protected File? get_mpd_conf () | ||
124 | 108 | { | ||
125 | 109 | // try ~/.mpdconf | ||
126 | 110 | string user_conf = turn_abs("~/.mpdconf"); | ||
127 | 111 | var ufile = File.new_for_path (user_conf); | ||
128 | 112 | if (ufile.query_exists ()) | ||
129 | 113 | { | ||
130 | 114 | return ufile; | ||
131 | 115 | } | ||
132 | 116 | // try /etc/mpd.conf | ||
133 | 117 | else | ||
134 | 118 | { | ||
135 | 119 | Utils.Logger.warning (this,"File '%s' doesn't exist", user_conf); | ||
136 | 120 | //not found, trying the other, hoping it's world-readable | ||
137 | 121 | var sfile = File.new_for_path ("/etc/mpd.conf"); | ||
138 | 122 | if (sfile.query_exists ()) | ||
139 | 123 | { | ||
140 | 124 | return sfile; | ||
141 | 125 | } | ||
142 | 126 | } | ||
143 | 127 | Utils.Logger.warning (this,"File '/etc/mpd.conf' doesn't exist"); | ||
144 | 128 | return null; | ||
145 | 129 | } | ||
146 | 130 | |||
147 | 131 | protected string? find_music_root (string? given_root) | ||
148 | 132 | { | ||
149 | 133 | try | ||
150 | 134 | { | ||
151 | 135 | if (given_root != null) | ||
152 | 136 | { | ||
153 | 137 | var g = File.new_for_path(given_root); | ||
154 | 138 | if (g.query_exists ()) | ||
155 | 139 | { | ||
156 | 140 | return given_root; | ||
157 | 141 | } | ||
158 | 142 | } | ||
159 | 143 | // the given path didn't check out | ||
160 | 144 | else | ||
161 | 145 | { | ||
162 | 146 | File file = get_mpd_conf(); | ||
163 | 147 | if (file != null) | ||
164 | 148 | { | ||
165 | 149 | var dis = new DataInputStream (file.read ()); | ||
166 | 150 | string line; | ||
167 | 151 | while ((line = dis.read_line (null)) != null) | ||
168 | 152 | { | ||
169 | 153 | //find the right line | ||
170 | 154 | Regex tag = new Regex("^music_directory.*$"); | ||
171 | 155 | if (tag.match (line)) | ||
172 | 156 | { | ||
173 | 157 | //capture the dir between the quotation marks | ||
174 | 158 | MatchInfo info; | ||
175 | 159 | Regex dir = new Regex("(?<=\")(.*?)(?=\")"); | ||
176 | 160 | if (dir.match (line, 0, out info)) | ||
177 | 161 | { | ||
178 | 162 | string found_root = turn_abs(info.fetch(0)) + "/"; | ||
179 | 163 | //make sure it exists | ||
180 | 164 | var r = File.new_for_path(found_root); | ||
181 | 165 | if (r.query_exists ()) | ||
182 | 166 | { | ||
183 | 167 | return found_root; | ||
184 | 168 | } | ||
185 | 169 | } | ||
186 | 170 | } | ||
187 | 171 | } | ||
188 | 172 | } | ||
189 | 173 | } | ||
190 | 174 | } | ||
191 | 175 | catch (Error e) | ||
192 | 176 | { | ||
193 | 177 | Utils.Logger.warning (this,"Music root not found: %s", e.message); | ||
194 | 178 | } | ||
195 | 179 | return null; | ||
196 | 180 | } | ||
197 | 181 | |||
198 | 182 | // convert uri to relative path | ||
199 | 183 | private string? path_from_uri (string uri) throws IOError | ||
200 | 184 | { | ||
201 | 185 | try | ||
202 | 186 | { | ||
203 | 187 | string path = Filename.from_uri(uri); | ||
204 | 188 | //make sure it exists | ||
205 | 189 | var p = File.new_for_path(path); | ||
206 | 190 | if (p.query_exists ()) | ||
207 | 191 | { | ||
208 | 192 | if (music_root != null) | ||
209 | 193 | { | ||
210 | 194 | if (music_root in path) | ||
211 | 195 | { | ||
212 | 196 | //strip music_root | ||
213 | 197 | return path[music_root.length:path.length]; | ||
214 | 198 | } | ||
215 | 199 | else | ||
216 | 200 | { | ||
217 | 201 | throw new IOError.NOT_FOUND("File not in mpd's music root"); | ||
218 | 202 | } | ||
219 | 203 | } | ||
220 | 204 | else | ||
221 | 205 | { | ||
222 | 206 | throw new IOError.NOT_FOUND("Music root not found"); | ||
223 | 207 | } | ||
224 | 208 | } | ||
225 | 209 | else | ||
226 | 210 | { | ||
227 | 211 | throw new IOError.NOT_FOUND("File %s not found", path); | ||
228 | 212 | } | ||
229 | 213 | } | ||
230 | 214 | catch (Error e) | ||
231 | 215 | { | ||
232 | 216 | Utils.Logger.warning (this,"Couldn't convert URI to filename: %s", e.message); | ||
233 | 217 | } | ||
234 | 218 | return null; | ||
235 | 219 | } | ||
236 | 220 | |||
237 | 221 | // run command | ||
238 | 222 | protected void run_command (string command, | ||
239 | 223 | string? qtype = null, string? sarg = null) throws IOError | ||
240 | 224 | { | ||
241 | 225 | Pid pid; | ||
242 | 226 | string complete_output = ""; | ||
243 | 227 | bool error_found = false; | ||
244 | 228 | string[] argv = {bin}; | ||
245 | 229 | if (host != null) | ||
246 | 230 | { | ||
247 | 231 | var s = new StringBuilder(); | ||
248 | 232 | if (passwd != null) | ||
249 | 233 | { | ||
250 | 234 | s.append_printf("%s@", passwd); | ||
251 | 235 | } | ||
252 | 236 | s.append_printf("%s", host); | ||
253 | 237 | argv += "-h"; | ||
254 | 238 | argv += s.str; | ||
255 | 239 | } | ||
256 | 240 | if (port != null) | ||
257 | 241 | { | ||
258 | 242 | argv += "-p"; | ||
259 | 243 | argv += port; | ||
260 | 244 | } | ||
261 | 245 | argv += command; | ||
262 | 246 | if (qtype != null) | ||
263 | 247 | { | ||
264 | 248 | argv += qtype; | ||
265 | 249 | if (sarg != null) | ||
266 | 250 | { | ||
267 | 251 | argv += sarg; | ||
268 | 252 | } | ||
269 | 253 | } | ||
270 | 254 | |||
271 | 255 | try | ||
272 | 256 | { | ||
273 | 257 | int read_fd; | ||
274 | 258 | // FIXME: probably a better way to do this | ||
275 | 259 | Process.spawn_async_with_pipes (null, argv, null, | ||
276 | 260 | SpawnFlags.SEARCH_PATH, | ||
277 | 261 | null, out pid, null, out read_fd); | ||
278 | 262 | UnixInputStream read_stream = new UnixInputStream (read_fd, true); | ||
279 | 263 | DataInputStream mpd_output = new DataInputStream (read_stream); | ||
280 | 264 | |||
281 | 265 | string? line = null; | ||
282 | 266 | do | ||
283 | 267 | { | ||
284 | 268 | line = mpd_output.read_line (null); | ||
285 | 269 | if (line != null) | ||
286 | 270 | { | ||
287 | 271 | complete_output += line; | ||
288 | 272 | } | ||
289 | 273 | } while (line != null); | ||
290 | 274 | // try and catch any 'error' line from mpc | ||
291 | 275 | Regex error = new Regex ("error:.*$"); | ||
292 | 276 | if (error.match (complete_output)) | ||
293 | 277 | { | ||
294 | 278 | error_found = true; | ||
295 | 279 | } | ||
296 | 280 | } | ||
297 | 281 | catch (Error err) | ||
298 | 282 | { | ||
299 | 283 | Utils.Logger.warning (this,"MPD is not available: %s", err.message); | ||
300 | 284 | } | ||
301 | 285 | if (error_found == true) | ||
302 | 286 | { | ||
303 | 287 | throw new IOError.CONNECTION_REFUSED (complete_output); | ||
304 | 288 | } | ||
305 | 289 | } | ||
306 | 290 | }//end of MpcEngine | ||
307 | 291 | |||
308 | 292 | |||
309 | 293 | /* SYNAPSE side (finally :p) */ | ||
310 | 294 | public class MpcActions: Object, Activatable, ItemProvider, ActionProvider | ||
311 | 295 | { | ||
312 | 296 | public bool enabled { get; set; default = true; } | ||
313 | 297 | |||
314 | 298 | public void activate () | ||
315 | 299 | { | ||
316 | 300 | } | ||
317 | 301 | |||
318 | 302 | public void deactivate () | ||
319 | 303 | { | ||
320 | 304 | } | ||
321 | 305 | |||
322 | 306 | static void register_plugin () | ||
323 | 307 | { | ||
324 | 308 | DataSink.PluginRegistry.get_default ().register_plugin ( | ||
325 | 309 | typeof (MpcActions), | ||
326 | 310 | _ ("Mpc"), | ||
327 | 311 | _ ("Control the Music Player Daemon."), | ||
328 | 312 | "mpc", | ||
329 | 313 | register_plugin, | ||
330 | 314 | Environment.find_program_in_path ("mpc") != null, | ||
331 | 315 | _ ("mpc is not installed") | ||
332 | 316 | ); | ||
333 | 317 | } | ||
334 | 318 | |||
335 | 319 | static construct | ||
336 | 320 | { | ||
337 | 321 | register_plugin (); | ||
338 | 322 | } | ||
339 | 323 | |||
340 | 324 | private abstract class MpcAction: Object, Match | ||
341 | 325 | { | ||
342 | 326 | // from Match interface | ||
343 | 327 | public string title { get; construct set; } | ||
344 | 328 | public string description { get; set; } | ||
345 | 329 | public string icon_name { get; construct set; } | ||
346 | 330 | public bool has_thumbnail { get; construct set; } | ||
347 | 331 | public string thumbnail_path { get; construct set; } | ||
348 | 332 | public MatchType match_type { get; construct set; } | ||
349 | 333 | |||
350 | 334 | public int default_relevancy { get; set; } | ||
351 | 335 | |||
352 | 336 | public abstract bool valid_for_match (Match match); | ||
353 | 337 | |||
354 | 338 | public abstract void execute_internal (Match? match); | ||
355 | 339 | public void execute (Match? match) | ||
356 | 340 | { | ||
357 | 341 | execute_internal (match); | ||
358 | 342 | } | ||
359 | 343 | public virtual int get_relevancy () | ||
360 | 344 | { | ||
361 | 345 | return default_relevancy + Match.Score.INCREMENT_LARGE; | ||
362 | 346 | } | ||
363 | 347 | } | ||
364 | 348 | |||
365 | 349 | private abstract class MpcControlMatch: Object, Match | ||
366 | 350 | { | ||
367 | 351 | // for Match interface | ||
368 | 352 | public string title { get; construct set; } | ||
369 | 353 | public string description { get; set; default = ""; } | ||
370 | 354 | public string icon_name { get; construct set; default = ""; } | ||
371 | 355 | public bool has_thumbnail { get; construct set; default = false; } | ||
372 | 356 | public string thumbnail_path { get; construct set; } | ||
373 | 357 | public MatchType match_type { get; construct set; } | ||
374 | 358 | |||
375 | 359 | public void execute (Match? match) | ||
376 | 360 | { | ||
377 | 361 | this.do_action (); | ||
378 | 362 | } | ||
379 | 363 | |||
380 | 364 | public abstract void do_action (); | ||
381 | 365 | |||
382 | 366 | } | ||
383 | 367 | |||
384 | 368 | /* MATCHES of Type.ACTION */ | ||
385 | 369 | private class Play: MpcControlMatch | ||
386 | 370 | { | ||
387 | 371 | public Play () | ||
388 | 372 | { | ||
389 | 373 | Object (title: _ ("Play"), | ||
390 | 374 | description: _ ("Start playback in MPD"), | ||
391 | 375 | icon_name: "media-playback-start", has_thumbnail: false, | ||
392 | 376 | match_type: MatchType.ACTION); | ||
393 | 377 | } | ||
394 | 378 | public override void do_action () | ||
395 | 379 | { | ||
396 | 380 | try | ||
397 | 381 | { | ||
398 | 382 | var player = new MpcEngine (); | ||
399 | 383 | player.play_pause (); | ||
400 | 384 | } | ||
401 | 385 | catch (IOError e) { | ||
402 | 386 | Utils.Logger.warning (this,"MPD is not available: %s", e.message); | ||
403 | 387 | } | ||
404 | 388 | } | ||
405 | 389 | } | ||
406 | 390 | |||
407 | 391 | private class Pause: Play | ||
408 | 392 | { | ||
409 | 393 | public Pause () | ||
410 | 394 | { | ||
411 | 395 | Object (title: _ ("Pause"), | ||
412 | 396 | description: _ ("Pause playback in MPD"), | ||
413 | 397 | icon_name: "media-playback-pause", has_thumbnail: false, | ||
414 | 398 | match_type: MatchType.ACTION); | ||
415 | 399 | } | ||
416 | 400 | } | ||
417 | 401 | |||
418 | 402 | private class Next: MpcControlMatch | ||
419 | 403 | { | ||
420 | 404 | public Next () | ||
421 | 405 | { | ||
422 | 406 | Object (title: _ ("Next"), | ||
423 | 407 | description: _ ("Plays the next song in MPD's playlist"), | ||
424 | 408 | icon_name: "media-skip-forward", has_thumbnail: false, | ||
425 | 409 | match_type: MatchType.ACTION); | ||
426 | 410 | } | ||
427 | 411 | |||
428 | 412 | public override void do_action () | ||
429 | 413 | { | ||
430 | 414 | try | ||
431 | 415 | { | ||
432 | 416 | var player = new MpcEngine (); | ||
433 | 417 | player.next (); | ||
434 | 418 | } | ||
435 | 419 | catch (IOError e) { | ||
436 | 420 | Utils.Logger.warning (this,"MPD is not available: %s", e.message); | ||
437 | 421 | } | ||
438 | 422 | } | ||
439 | 423 | |||
440 | 424 | } | ||
441 | 425 | private class Previous: MpcControlMatch | ||
442 | 426 | { | ||
443 | 427 | public Previous () | ||
444 | 428 | { | ||
445 | 429 | Object (title: _ ("Previous"), | ||
446 | 430 | description: _ ("Plays the previous song in MPD's playlist"), | ||
447 | 431 | icon_name: "media-skip-backward", has_thumbnail: false, | ||
448 | 432 | match_type: MatchType.ACTION); | ||
449 | 433 | } | ||
450 | 434 | |||
451 | 435 | public override void do_action () | ||
452 | 436 | { | ||
453 | 437 | try | ||
454 | 438 | { | ||
455 | 439 | var player = new MpcEngine (); | ||
456 | 440 | player.previous (); | ||
457 | 441 | } | ||
458 | 442 | catch (IOError e) { | ||
459 | 443 | Utils.Logger.warning (this,"MPD is not available: %s", e.message); | ||
460 | 444 | } | ||
461 | 445 | } | ||
462 | 446 | } | ||
463 | 447 | |||
464 | 448 | private class Stop: MpcControlMatch | ||
465 | 449 | { | ||
466 | 450 | public Stop () | ||
467 | 451 | { | ||
468 | 452 | Object (title: _ ("Stop"), | ||
469 | 453 | description: _ ("Stop playback in MPD"), | ||
470 | 454 | icon_name: "media-stop", has_thumbnail: false, | ||
471 | 455 | match_type: MatchType.ACTION); | ||
472 | 456 | } | ||
473 | 457 | |||
474 | 458 | public override void do_action () | ||
475 | 459 | { | ||
476 | 460 | try | ||
477 | 461 | { | ||
478 | 462 | var player = new MpcEngine (); | ||
479 | 463 | player.stop (); | ||
480 | 464 | } | ||
481 | 465 | catch (IOError e) { | ||
482 | 466 | Utils.Logger.warning (this, "MPD is not available: %s", e.message); | ||
483 | 467 | } | ||
484 | 468 | } | ||
485 | 469 | } | ||
486 | 470 | |||
487 | 471 | /* ACTIONS FOR Music files */ | ||
488 | 472 | private class AddToPlaylist: MpcAction | ||
489 | 473 | { | ||
490 | 474 | public AddToPlaylist () | ||
491 | 475 | { | ||
492 | 476 | Object (title: _ ("Enqueue in MPD"), | ||
493 | 477 | description: _ ("Add the song to MPD's playlist"), | ||
494 | 478 | icon_name: "media-playback-start", has_thumbnail: false, | ||
495 | 479 | match_type: MatchType.ACTION, | ||
496 | 480 | default_relevancy: Match.Score.AVERAGE); | ||
497 | 481 | } | ||
498 | 482 | |||
499 | 483 | public override void execute_internal (Match? match) | ||
500 | 484 | { | ||
501 | 485 | return_if_fail (match.match_type == MatchType.GENERIC_URI); | ||
502 | 486 | UriMatch uri = match as UriMatch; | ||
503 | 487 | return_if_fail ((uri.file_type & QueryFlags.AUDIO) != 0); | ||
504 | 488 | |||
505 | 489 | try | ||
506 | 490 | { | ||
507 | 491 | var player = new MpcEngine (); | ||
508 | 492 | player.enqueue (uri.uri); | ||
509 | 493 | } | ||
510 | 494 | catch (IOError e) { | ||
511 | 495 | Utils.Logger.warning (this, "MPD is not available: %s", e.message); | ||
512 | 496 | } | ||
513 | 497 | |||
514 | 498 | } | ||
515 | 499 | |||
516 | 500 | public override bool valid_for_match (Match match) | ||
517 | 501 | { | ||
518 | 502 | switch (match.match_type) | ||
519 | 503 | { | ||
520 | 504 | case MatchType.GENERIC_URI: | ||
521 | 505 | UriMatch uri = match as UriMatch; | ||
522 | 506 | if ((uri.file_type & QueryFlags.AUDIO) != 0) | ||
523 | 507 | return true; | ||
524 | 508 | else | ||
525 | 509 | return false; | ||
526 | 510 | default: | ||
527 | 511 | return false; | ||
528 | 512 | } | ||
529 | 513 | } | ||
530 | 514 | } | ||
531 | 515 | private class PlayNow: MpcAction | ||
532 | 516 | { | ||
533 | 517 | public PlayNow () | ||
534 | 518 | { | ||
535 | 519 | Object (title: _ ("Play in MPD"), | ||
536 | 520 | description: _ ("Clears the current playlist and plays the song"), | ||
537 | 521 | icon_name: "media-playback-start", has_thumbnail: false, | ||
538 | 522 | match_type: MatchType.ACTION, | ||
539 | 523 | default_relevancy: Match.Score.ABOVE_AVERAGE); | ||
540 | 524 | } | ||
541 | 525 | |||
542 | 526 | public override void execute_internal (Match? match) | ||
543 | 527 | { | ||
544 | 528 | return_if_fail (match.match_type == MatchType.GENERIC_URI); | ||
545 | 529 | UriMatch uri = match as UriMatch; | ||
546 | 530 | return_if_fail ((uri.file_type & QueryFlags.AUDIO) != 0 ); | ||
547 | 531 | |||
548 | 532 | try | ||
549 | 533 | { | ||
550 | 534 | var player = new MpcEngine (); | ||
551 | 535 | player.play_now (uri.uri); | ||
552 | 536 | } | ||
553 | 537 | catch (IOError e) { | ||
554 | 538 | Utils.Logger.warning (this, "MPD is not available: %s", e.message); | ||
555 | 539 | } | ||
556 | 540 | } | ||
557 | 541 | |||
558 | 542 | public override bool valid_for_match (Match match) | ||
559 | 543 | { | ||
560 | 544 | switch (match.match_type) | ||
561 | 545 | { | ||
562 | 546 | case MatchType.GENERIC_URI: | ||
563 | 547 | UriMatch uri = match as UriMatch; | ||
564 | 548 | if ((uri.file_type & QueryFlags.AUDIO) != 0) | ||
565 | 549 | return true; | ||
566 | 550 | else | ||
567 | 551 | return false; | ||
568 | 552 | default: | ||
569 | 553 | return false; | ||
570 | 554 | } | ||
571 | 555 | } | ||
572 | 556 | } | ||
573 | 557 | |||
574 | 558 | private Gee.List<MpcAction> actions; | ||
575 | 559 | private Gee.List<MpcControlMatch> matches; | ||
576 | 560 | |||
577 | 561 | construct | ||
578 | 562 | { | ||
579 | 563 | actions = new Gee.ArrayList<MpcAction> (); | ||
580 | 564 | matches = new Gee.ArrayList<MpcControlMatch> (); | ||
581 | 565 | |||
582 | 566 | actions.add (new PlayNow()); | ||
583 | 567 | actions.add (new AddToPlaylist()); | ||
584 | 568 | |||
585 | 569 | matches.add (new Play ()); | ||
586 | 570 | matches.add (new Stop ()); | ||
587 | 571 | matches.add (new Pause ()); | ||
588 | 572 | matches.add (new Previous ()); | ||
589 | 573 | matches.add (new Next ()); | ||
590 | 574 | } | ||
591 | 575 | |||
592 | 576 | public async ResultSet? search (Query q) throws SearchError | ||
593 | 577 | { | ||
594 | 578 | // we only search for actions | ||
595 | 579 | if (!(QueryFlags.ACTIONS in q.query_type)) return null; | ||
596 | 580 | |||
597 | 581 | var result = new ResultSet (); | ||
598 | 582 | |||
599 | 583 | var matchers = Query.get_matchers_for_query (q.query_string, 0, | ||
600 | 584 | RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS); | ||
601 | 585 | |||
602 | 586 | foreach (var action in matches) | ||
603 | 587 | { | ||
604 | 588 | foreach (var matcher in matchers) | ||
605 | 589 | { | ||
606 | 590 | if (matcher.key.match (action.title)) | ||
607 | 591 | { | ||
608 | 592 | result.add (action, matcher.value - Match.Score.INCREMENT_SMALL); | ||
609 | 593 | break; | ||
610 | 594 | } | ||
611 | 595 | } | ||
612 | 596 | } | ||
613 | 597 | |||
614 | 598 | q.check_cancellable (); | ||
615 | 599 | |||
616 | 600 | return result; | ||
617 | 601 | } | ||
618 | 602 | |||
619 | 603 | public ResultSet? find_for_match (Query query, Match match) | ||
620 | 604 | { | ||
621 | 605 | bool query_empty = query.query_string == ""; | ||
622 | 606 | var results = new ResultSet (); | ||
623 | 607 | |||
624 | 608 | if (query_empty) | ||
625 | 609 | { | ||
626 | 610 | foreach (var action in actions) | ||
627 | 611 | { | ||
628 | 612 | if (action.valid_for_match (match)) | ||
629 | 613 | { | ||
630 | 614 | results.add (action, action.get_relevancy ()); | ||
631 | 615 | } | ||
632 | 616 | } | ||
633 | 617 | } | ||
634 | 618 | else | ||
635 | 619 | { | ||
636 | 620 | var matchers = Query.get_matchers_for_query (query.query_string, 0, | ||
637 | 621 | RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS); | ||
638 | 622 | foreach (var action in actions) | ||
639 | 623 | { | ||
640 | 624 | if (!action.valid_for_match (match)) continue; | ||
641 | 625 | foreach (var matcher in matchers) | ||
642 | 626 | { | ||
643 | 627 | if (matcher.key.match (action.title)) | ||
644 | 628 | { | ||
645 | 629 | results.add (action, matcher.value); | ||
646 | 630 | break; | ||
647 | 631 | } | ||
648 | 632 | } | ||
649 | 633 | } | ||
650 | 634 | } | ||
651 | 635 | |||
652 | 636 | return results; | ||
653 | 637 | } | ||
654 | 638 | } | ||
655 | 639 | } | ||
656 | 0 | 640 | ||
657 | === modified file 'src/ui/synapse-main.vala' | |||
658 | --- src/ui/synapse-main.vala 2011-05-05 00:07:47 +0000 | |||
659 | +++ src/ui/synapse-main.vala 2011-05-31 10:31:30 +0000 | |||
660 | @@ -178,6 +178,7 @@ | |||
661 | 178 | // typeof (FileOpPlugin), | 178 | // typeof (FileOpPlugin), |
662 | 179 | // typeof (PidginPlugin), | 179 | // typeof (PidginPlugin), |
663 | 180 | // typeof (ChatActions), | 180 | // typeof (ChatActions), |
664 | 181 | typeof (MpcActions), | ||
665 | 181 | #if HAVE_ZEITGEIST | 182 | #if HAVE_ZEITGEIST |
666 | 182 | typeof (ZeitgeistPlugin), | 183 | typeof (ZeitgeistPlugin), |
667 | 183 | #endif | 184 | #endif |
First of all, thank you for your contribution! :)
Some comments:
1)
MpcEngine class is instantiated each time I execute an action.
But MpcEngine doesn't have "attributes" that needs to be instantiated.
So I suggest to turn each method and attribute of MpcEnginge into a static one.
In example:
private static string bin = "mpc"; //this can be also "const"
public static void play_pause ()...
In this way you can call directly: play_pause ();
MpcEngine.
2) what's the meaning of
>>search the database for a "type" and turn results to uris on the fly<< ?
3) Synapse's configuration capabilities will come asap (mhr3 and I are very busy in this moment)