No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2006 Jonathan Matthew
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * The Rhythmbox authors hereby grant permission for non-GPL compatible
11 * GStreamer plugins to be used and distributed together with GStreamer
12 * and Rhythmbox. This permission is above and beyond the permissions granted
13 * by the GPL license by which Rhythmbox is covered. If you modify this code
14 * you may extend this exception to your version of the code, but you are not
15 * obligated to do so. If you do not wish to do so, delete this exception
16 * statement from your version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
29 #include <config.h>
30
31 #include <locale.h>
32 #include <stdlib.h>
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <glib-object.h>
36 #include <gio/gio.h>
37
38 #include "rb-debug.h"
39
40 static gboolean debug = FALSE;
41
42 static gboolean no_start = FALSE;
43 static gboolean quit = FALSE;
44 static gboolean check_running = FALSE;
45
46 static gboolean no_present = FALSE;
47
48 static gboolean next = FALSE;
49 static gboolean previous = FALSE;
50 static gint32 seek = 0;
51
52 static gboolean play = FALSE;
53 static gboolean do_pause = FALSE;
54 static gboolean play_pause = FALSE;
55 static gboolean stop = FALSE;
56
57 static gboolean enqueue = FALSE;
58
59 static gboolean clear_queue = FALSE;
60
61 static gchar *select_source = NULL;
62 static gchar *activate_source = NULL;
63 static gchar *play_source = NULL;
64 static gchar *play_uri = NULL;
65 static gboolean print_playing = FALSE;
66 static gchar *print_playing_format = NULL;
67
68 static gdouble set_volume = -1.0;
69 static gboolean volume_up = FALSE;
70 static gboolean volume_down = FALSE;
71 static gboolean print_volume = FALSE;
72 /*static gboolean mute = FALSE;
73 static gboolean unmute = FALSE; */
74 static gdouble set_rating = -1.0;
75
76 static gchar **other_stuff = NULL;
77
78 static GOptionEntry args[] = {
79 { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, NULL, NULL },
80
81 { "no-start", 0, 0, G_OPTION_ARG_NONE, &no_start, N_("Don't start a new instance of Rhythmbox"), NULL },
82 { "quit", 0, 0, G_OPTION_ARG_NONE, &quit, N_("Quit Rhythmbox"), NULL },
83 { "check-running", 0, 0, G_OPTION_ARG_NONE, &check_running, N_("Check if Rhythmbox is already running"), NULL },
84
85 { "no-present", 0, 0, G_OPTION_ARG_NONE, &no_present, N_("Don't present an existing Rhythmbox window"), NULL },
86
87 { "next", 0, 0, G_OPTION_ARG_NONE, &next, N_("Jump to next song"), NULL },
88 { "previous", 0, 0, G_OPTION_ARG_NONE, &previous, N_("Jump to previous song"), NULL },
89 { "seek", 0, 0, G_OPTION_ARG_INT64, &seek, N_("Seek in current track"), NULL },
90
91 { "play", 0, 0, G_OPTION_ARG_NONE, &play, N_("Resume playback if currently paused"), NULL },
92 { "pause", 0, 0, G_OPTION_ARG_NONE, &do_pause, N_("Pause playback if currently playing"), NULL },
93 { "play-pause", 0, 0, G_OPTION_ARG_NONE, &play_pause, N_("Toggle play/pause mode"), NULL },
94 /* { "stop", 0, 0, G_OPTION_ARG_NONE, &stop, N_("Stop playback"), NULL }, */
95
96 { "play-uri", 0, 0, G_OPTION_ARG_FILENAME, &play_uri, N_("Play a specified URI, importing it if necessary"), N_("URI to play")},
97 { "enqueue", 0, 0, G_OPTION_ARG_NONE, &enqueue, N_("Add specified tracks to the play queue"), NULL },
98 { "clear-queue", 0, 0, G_OPTION_ARG_NONE, &clear_queue, N_("Empty the play queue before adding new tracks"), NULL },
99
100 { "print-playing", 0, 0, G_OPTION_ARG_NONE, &print_playing, N_("Print the title and artist of the playing song"), NULL },
101 { "print-playing-format", 0, 0, G_OPTION_ARG_STRING, &print_playing_format, N_("Print formatted details of the song"), NULL },
102 { "select-source", 0, 0, G_OPTION_ARG_STRING, &select_source, N_("Select the source matching the specified URI"), N_("Source to select")},
103 { "activate-source", 0, 0, G_OPTION_ARG_STRING, &activate_source, N_("Activate the source matching the specified URI"), N_("Source to activate")},
104 { "play-source", 0, 0, G_OPTION_ARG_STRING, &play_source, N_("Play from the source matching the specified URI"), N_("Source to play from")},
105
106 { "set-volume", 0, 0, G_OPTION_ARG_DOUBLE, &set_volume, N_("Set the playback volume"), NULL },
107 { "volume-up", 0, 0, G_OPTION_ARG_NONE, &volume_up, N_("Increase the playback volume"), NULL },
108 { "volume-down", 0, 0, G_OPTION_ARG_NONE, &volume_down, N_("Decrease the playback volume"), NULL },
109 { "print-volume", 0, 0, G_OPTION_ARG_NONE, &print_volume, N_("Print the current playback volume"), NULL },
110 /* { "mute", 0, 0, G_OPTION_ARG_NONE, &mute, N_("Mute playback"), NULL },
111 { "unmute", 0, 0, G_OPTION_ARG_NONE, &unmute, N_("Unmute playback"), NULL }, */
112 { "set-rating", 0, 0, G_OPTION_ARG_DOUBLE, &set_rating, N_("Set the rating of the current song"), NULL },
113
114 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &other_stuff, NULL, NULL },
115
116 { NULL }
117 };
118
119 static gboolean
120 annoy (GError **error)
121 {
122 if (*error) {
123 g_warning ("%s", (*error)->message);
124 g_clear_error (error);
125 return TRUE;
126 }
127
128 return FALSE;
129 }
130
131
132 static char *
133 rb_make_duration_string (gint64 duration)
134 {
135 char *str;
136 int hours, minutes, seconds;
137
138 duration /= G_USEC_PER_SEC;
139 hours = duration / (60 * 60);
140 minutes = (duration - (hours * 60 * 60)) / 60;
141 seconds = duration % 60;
142
143 if (hours == 0 && minutes == 0 && seconds == 0)
144 str = g_strdup (_("Unknown"));
145 else if (hours == 0)
146 str = g_strdup_printf (_("%d:%02d"), minutes, seconds);
147 else
148 str = g_strdup_printf (_("%d:%02d:%02d"), hours, minutes, seconds);
149
150 return str;
151 }
152
153 /*
154 * Parse a filename pattern and replace markers with values from a TrackDetails
155 * structure.
156 *
157 * Valid markers so far are:
158 * %at -- album title
159 * %aa -- album artist
160 * %aA -- album artist (lowercase)
161 * %as -- album artist sortname
162 * %aS -- album artist sortname (lowercase)
163 * %ay -- album year
164 * %ag -- album genre
165 * %aG -- album genre (lowercase)
166 * %an -- album disc number
167 * %aN -- album disc number, zero padded
168 * %tn -- track number (i.e 8)
169 * %tN -- track number, zero padded (i.e 08)
170 * %tt -- track title
171 * %ta -- track artist
172 * %tA -- track artist (lowercase)
173 * %ts -- track artist sortname
174 * %tS -- track artist sortname (lowercase)
175 * %td -- track duration
176 * %te -- track elapsed time
177 * %tb -- track bitrate
178 * %st -- stream title
179 */
180 static char *
181 parse_pattern (const char *pattern, GHashTable *properties, gint64 elapsed)
182 {
183 /* p is the pattern iterator, i is a general purpose iterator */
184 const char *p;
185 char *temp;
186 GString *s;
187
188 if (pattern == NULL || pattern[0] == 0)
189 return g_strdup (" ");
190
191 s = g_string_new (NULL);
192
193 p = pattern;
194 while (*p) {
195 char *string = NULL;
196 const char **strv = NULL;
197 GVariant *value = NULL;
198
199 /* If not a % marker, copy and continue */
200 if (*p != '%') {
201 g_string_append_c (s, *p++);
202 /* Explicit increment as we continue past the increment */
203 continue;
204 }
205
206 /* Is a % marker, go to next and see what to do */
207 switch (*++p) {
208 case '%':
209 /*
210 * Literal %
211 */
212 g_string_append_c (s, '%');
213 break;
214 case 'a':
215 /*
216 * Album tag
217 */
218 switch (*++p) {
219 case 't':
220 value = g_hash_table_lookup (properties, "xesam:album");
221 if (value)
222 string = g_variant_dup_string (value, NULL);
223 break;
224 case 'T':
225 value = g_hash_table_lookup (properties, "xesam:album");
226 if (value)
227 string = g_utf8_strdown (g_variant_get_string (value, NULL), -1);
228 break;
229 case 'a':
230 value = g_hash_table_lookup (properties, "xesam:artist");
231 if (value) {
232 strv = g_variant_get_strv (value, NULL);
233 string = g_strdup (strv[0]);
234 }
235 break;
236 case 'A':
237 value = g_hash_table_lookup (properties, "xesam:artist");
238 if (value) {
239 strv = g_variant_get_strv (value, NULL);
240 string = g_utf8_strdown (strv[0], -1);
241 }
242 break;
243 case 's':
244 value = g_hash_table_lookup (properties, "rhythmbox:albumArtistSortname");
245 if (value)
246 string = g_variant_dup_string (value, NULL);
247 break;
248 case 'S':
249 value = g_hash_table_lookup (properties, "rhythmbox:albumArtistSortname");
250 if (value)
251 string = g_utf8_strdown (g_variant_get_string (value, NULL), -1);
252 break;
253 case 'y':
254 /* Release year */
255 value = g_hash_table_lookup (properties, "xesam:contentCreated");
256 if (value) {
257 const char *iso8601;
258 GTimeVal tv;
259
260 iso8601 = g_variant_get_string (value, NULL);
261 if (g_time_val_from_iso8601 (iso8601, &tv)) {
262 GDate d;
263 g_date_set_time_val (&d, &tv);
264
265 string = g_strdup_printf ("%u", g_date_get_year (&d));
266 }
267 }
268 break;
269 /* Disc number */
270 case 'n':
271 value = g_hash_table_lookup (properties, "xesam:discNumber");
272 if (value)
273 string = g_strdup_printf ("%u", g_variant_get_int32 (value));
274 break;
275 case 'N':
276 value = g_hash_table_lookup (properties, "xesam:discNumber");
277 if (value)
278 string = g_strdup_printf ("%02u", g_variant_get_int32 (value));
279 break;
280 /* genre */
281 case 'g':
282 value = g_hash_table_lookup (properties, "xesam:genre");
283 if (value) {
284 strv = g_variant_get_strv (value, NULL);
285 string = g_strdup (strv[0]);
286 }
287 break;
288 case 'G':
289 value = g_hash_table_lookup (properties, "xesam:genre");
290 if (value) {
291 strv = g_variant_get_strv (value, NULL);
292 string = g_utf8_strdown (strv[0], -1);
293 }
294 break;
295 default:
296 string = g_strdup_printf ("%%a%c", *p);
297 }
298
299 break;
300
301 case 't':
302 /*
303 * Track tag
304 */
305 switch (*++p) {
306 case 't':
307 value = g_hash_table_lookup (properties, "rhythmbox:streamTitle");
308 if (value == NULL)
309 value = g_hash_table_lookup (properties, "xesam:title");
310 if (value)
311 string = g_variant_dup_string (value, NULL);
312 break;
313 case 'T':
314 value = g_hash_table_lookup (properties, "rhythmbox:streamTitle");
315 if (value == NULL)
316 value = g_hash_table_lookup (properties, "xesam:title");
317 if (value)
318 string = g_utf8_strdown (g_variant_get_string (value, NULL), -1);
319 break;
320 case 'a':
321 value = g_hash_table_lookup (properties, "xesam:artist");
322 if (value) {
323 strv = g_variant_get_strv (value, NULL);
324 string = g_strdup (strv[0]);
325 }
326 break;
327 case 'A':
328 value = g_hash_table_lookup (properties, "xesam:artist");
329 if (value) {
330 strv = g_variant_get_strv (value, NULL);
331 string = g_utf8_strdown (strv[0], -1);
332 }
333 break;
334 case 's':
335 value = g_hash_table_lookup (properties, "rhythmbox:artistSortname");
336 if (value)
337 string = g_variant_dup_string (value, NULL);
338 break;
339 case 'S':
340 value = g_hash_table_lookup (properties, "rhythmbox:artistSortname");
341 if (value)
342 string = g_utf8_strdown (g_variant_get_string (value, NULL), -1);
343 break;
344 case 'n':
345 /* Track number */
346 value = g_hash_table_lookup (properties, "xesam:trackNumber");
347 if (value)
348 string = g_strdup_printf ("%u", g_variant_get_int32 (value));
349 break;
350 case 'N':
351 /* Track number, zero-padded */
352 value = g_hash_table_lookup (properties, "xesam:trackNumber");
353 if (value)
354 string = g_strdup_printf ("%02u", g_variant_get_int32 (value));
355 break;
356 case 'd':
357 /* Track duration */
358 value = g_hash_table_lookup (properties, "mpris:length");
359 if (value)
360 string = rb_make_duration_string (g_variant_get_int64 (value));
361 break;
362 case 'e':
363 /* Track elapsed time */
364 string = rb_make_duration_string (elapsed);
365 break;
366 case 'b':
367 /* Track bitrate */
368 value = g_hash_table_lookup (properties, "xesam:audioBitrate");
369 if (value)
370 string = g_strdup_printf ("%u", g_variant_get_int32 (value) / 1024);
371 break;
372
373 default:
374 string = g_strdup_printf ("%%t%c", *p);
375 }
376
377 break;
378
379 case 's':
380 /*
381 * Stream tag
382 */
383 switch (*++p) {
384 case 't':
385 value = g_hash_table_lookup (properties, "rhythmbox:streamTitle");
386 if (value) {
387 value = g_hash_table_lookup (properties, "xesam:title");
388 if (value) {
389 string = g_variant_dup_string (value, NULL);
390 }
391 }
392 break;
393 default:
394 string = g_strdup_printf ("%%s%c", *p);
395 }
396 break;
397
398 default:
399 string = g_strdup_printf ("%%%c", *p);
400 }
401
402 if (string)
403 g_string_append (s, string);
404 g_free (string);
405
406 ++p;
407 }
408
409 temp = s->str;
410 g_string_free (s, FALSE);
411 return temp;
412 }
413
414
415 static GHashTable *
416 get_playing_song_info (GDBusProxy *mpris)
417 {
418 GHashTable *properties;
419 GVariant *prop;
420 GVariant *metadata;
421 GVariantIter iter;
422 GVariant *value;
423 char *key;
424 GError *error = NULL;
425
426 prop = g_dbus_proxy_call_sync (mpris,
427 "org.freedesktop.DBus.Properties.Get",
428 g_variant_new ("(ss)", "org.mpris.MediaPlayer2.Player", "Metadata"),
429 G_DBUS_CALL_FLAGS_NONE,
430 -1,
431 NULL,
432 &error);
433 if (annoy (&error)) {
434 return NULL;
435 }
436
437 g_variant_get (prop, "(v)", &metadata);
438
439 properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
440 g_variant_iter_init (&iter, metadata);
441 while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) {
442 g_hash_table_insert (properties, g_strdup (key), g_variant_ref (value));
443 }
444
445 g_variant_unref (prop);
446 return properties;
447 }
448
449 static void
450 print_playing_song (GDBusProxy *mpris, const char *format)
451 {
452 GHashTable *properties;
453 GVariant *v;
454 gint64 elapsed = 0;
455 char *string;
456
457 properties = get_playing_song_info (mpris);
458 if (properties == NULL) {
459 g_print ("%s\n", _("Not playing"));
460 return;
461 }
462
463 v = g_dbus_proxy_get_cached_property (mpris, "Position");
464 if (v != NULL) {
465 elapsed = g_variant_get_int64 (v);
466 g_variant_unref (v);
467 }
468
469 string = parse_pattern (format, properties, elapsed);
470 g_print ("%s\n", string);
471 g_hash_table_destroy (properties);
472 g_free (string);
473 }
474
475 static void
476 print_playing_song_default (GDBusProxy *mpris)
477 {
478 GHashTable *properties;
479 char *string;
480
481 properties = get_playing_song_info (mpris);
482 if (properties == NULL) {
483 g_print ("%s\n", _("Not playing"));
484 return;
485 }
486
487 if (g_hash_table_lookup (properties, "rhythmbox:streamTitle") != NULL) {
488 string = parse_pattern ("%st (%tt)", properties, 0);
489 } else {
490 string = parse_pattern ("%ta - %tt", properties, 0);
491 }
492
493 g_print ("%s\n", string);
494 g_hash_table_destroy (properties);
495 g_free (string);
496 }
497
498 static void
499 rate_song (GDBusProxy *mpris, gdouble song_rating)
500 {
501 GHashTable *properties;
502 GVariantBuilder props;
503 GVariant *v;
504 GError *error = NULL;
505
506 properties = get_playing_song_info (mpris);
507 if (properties == NULL) {
508 rb_debug ("can't set rating when not playing");
509 return;
510 }
511
512 v = g_hash_table_lookup (properties, "xesam:url");
513 if (v == NULL) {
514 rb_debug ("can't set rating, no url");
515 return;
516 }
517
518 g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
519 g_variant_builder_add (&props, "{sv}", "rating", g_variant_new_double (song_rating));
520
521 g_dbus_connection_call_sync (g_dbus_proxy_get_connection (mpris),
522 "org.gnome.Rhythmbox3",
523 "/org/gnome/Rhythmbox3/RhythmDB",
524 "org.gnome.Rhythmbox3.RhythmDB",
525 "SetEntryProperties",
526 g_variant_new ("(sa{sv})", g_variant_get_string (v, NULL), &props),
527 NULL,
528 G_DBUS_CALL_FLAGS_NONE,
529 -1,
530 NULL,
531 &error);
532 if (error != NULL) {
533 g_warning ("Error setting rating on %s: %s",
534 g_variant_get_string (v, NULL),
535 error->message);
536 g_clear_error (&error);
537 }
538 g_hash_table_destroy (properties);
539 }
540
541 static void
542 state_changed_cb (GActionGroup *action, const char *action_name, GVariant *state, GMainLoop *loop)
543 {
544 if (g_strcmp0 (action_name, "LoadURI") == 0) {
545 gboolean loaded, scanned;
546
547 g_variant_get (state, "(bb)", &loaded, &scanned);
548 if (loaded && scanned) {
549 /* give it a tiny bit longer to populate sources etc. */
550 g_timeout_add (1500, (GSourceFunc) g_main_loop_quit, loop);
551 }
552 }
553 }
554
555 static void
556 state_changed_signal_cb (GDBusProxy *proxy, const char *sender_name, const char *signal_name, GVariant *parameters, GMainLoop *loop)
557 {
558 const char *action;
559 GVariant *state;
560 if (g_strcmp0 (signal_name, "StateChanged") != 0) {
561 return;
562 }
563
564 g_variant_get (parameters, "(sv)", &action, &state);
565 if (g_strcmp0 (action, "LoadURI") == 0) {
566 GApplication *app;
567 app = g_object_get_data (G_OBJECT (proxy), "actual-app");
568 state_changed_cb (G_ACTION_GROUP (app), action, state, loop);
569 }
570 g_variant_unref (state);
571 }
572
573 static gboolean
574 proxy_has_name_owner (GDBusProxy *proxy)
575 {
576 gboolean has_owner;
577 char *owner = g_dbus_proxy_get_name_owner (proxy);
578
579 has_owner = (owner != NULL);
580 g_free (owner);
581 return has_owner;
582 }
583
584
585 int
586 main (int argc, char **argv)
587 {
588 GOptionContext *context;
589 GError *error = NULL;
590 GDBusConnection *bus;
591 GDBusProxy *mpris;
592 GDBusProxy *queue;
593 GApplication *app;
594 gboolean loaded;
595 gboolean scanned;
596 GVariant *state;
597
598 #ifdef ENABLE_NLS
599 /* initialize i18n */
600 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
601 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
602 textdomain (GETTEXT_PACKAGE);
603 #endif
604 /* setup */
605 setlocale (LC_ALL, "");
606 g_type_init ();
607 g_set_prgname ("rhythmbox-client");
608
609 /* parse arguments */
610 context = g_option_context_new (NULL);
611 g_option_context_add_main_entries (context, args, NULL);
612 g_option_context_parse (context, &argc, &argv, &error);
613 if (annoy (&error))
614 exit (1);
615
616 rb_debug_init (debug);
617
618 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
619 /* check if it's running before registering the application */
620 if (no_start || check_running || quit) {
621 GDBusProxy *app_proxy;
622 app_proxy = g_dbus_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
623 "org.gnome.Rhythmbox3",
624 "/org/gnome/Rhythmbox3",
625 "org.gtk.Actions",
626 NULL,
627 &error);
628 if (app_proxy == NULL || proxy_has_name_owner (app_proxy) == FALSE) {
629 rb_debug ("not running");
630 if (check_running) {
631 exit (2);
632 }
633 exit (0);
634 } else if (check_running) {
635 rb_debug ("running instance found");
636 exit (0);
637 }
638 g_object_unref (app_proxy);
639 }
640
641 app = g_application_new ("org.gnome.Rhythmbox3", G_APPLICATION_IS_LAUNCHER);
642 if (g_application_register (app, NULL, &error) == FALSE) {
643 if (check_running) {
644 rb_debug ("no running instance found");
645 exit (2);
646 } else if (quit) {
647 rb_debug ("no existing instance to quit");
648 exit (0);
649 }
650
651 rb_debug ("uh.. what?");
652 exit (0);
653 }
654
655 /* wait until it's ready to accept control */
656 state = g_action_group_get_action_state (G_ACTION_GROUP (app), "LoadURI");
657 if (state == NULL) {
658 rb_debug ("couldn't get app startup state");
659 exit (0);
660 }
661
662 g_variant_get (state, "(bb)", &loaded, &scanned);
663 if ((loaded && scanned) == FALSE) {
664 GMainLoop *loop;
665 GDBusProxy *app_proxy;
666
667 rb_debug ("waiting for app startup");
668 loop = g_main_loop_new (NULL, FALSE);
669 g_signal_connect (app, "action-state-changed", G_CALLBACK (state_changed_cb), loop);
670
671 /* dbus implementation of GApplication doesn't do action state updates yet */
672 app_proxy = g_dbus_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
673 "org.gnome.Rhythmbox3",
674 "/org/gnome/Rhythmbox3",
675 "org.gtk.Actions",
676 NULL,
677 &error);
678 if (app_proxy == NULL || proxy_has_name_owner (app_proxy) == FALSE) {
679 g_warning ("unable to wait for app startup: %s", error->message);
680 g_clear_error (&error);
681 } else {
682 g_object_set_data (G_OBJECT (app_proxy), "actual-app", app);
683 g_signal_connect (app_proxy, "g-signal", G_CALLBACK (state_changed_signal_cb), loop);
684 g_main_loop_run (loop);
685 rb_debug ("app is now started enough");
686 }
687 }
688
689 /* create proxies */
690 mpris = g_dbus_proxy_new_sync (bus,
691 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
692 NULL,
693 "org.mpris.MediaPlayer2.rhythmbox",
694 "/org/mpris/MediaPlayer2",
695 "org.mpris.MediaPlayer2.Player",
696 NULL,
697 &error);
698 if (mpris == NULL || proxy_has_name_owner (mpris) == FALSE) {
699 g_warning ("MPRIS D-Bus interface not available, some things won't work");
700 if (next || previous || (seek != 0) || play || do_pause || play_pause || stop || volume_up || volume_down || (set_volume > -0.01)) {
701 exit (1);
702 }
703 }
704
705 queue = g_dbus_proxy_new_sync (bus,
706 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
707 NULL,
708 "org.gnome.Rhythmbox3",
709 "/org/gnome/Rhythmbox3/PlayQueue",
710 "org.gnome.Rhythmbox3.PlayQueue",
711 NULL,
712 &error);
713 if (queue == NULL || proxy_has_name_owner (queue) == FALSE) {
714 g_warning ("Play queue interface not available, some things won't work");
715 if (enqueue || clear_queue) {
716 exit (1);
717 }
718 }
719
720 /* activate or quit */
721 if (quit) {
722 rb_debug ("quitting existing instance");
723 g_action_group_activate_action (G_ACTION_GROUP (app), "Quit", NULL);
724 exit (0);
725 }
726
727 /* don't present if we're doing something else */
728 if (next || previous || (seek != 0) ||
729 clear_queue ||
730 play_uri || other_stuff ||
731 play || do_pause || play_pause || stop ||
732 print_playing || print_playing_format ||
733 (set_volume > -0.01) || volume_up || volume_down || print_volume /*|| mute || unmute*/ || (set_rating > -0.01))
734 no_present = TRUE;
735
736 /* present */
737 if (!no_present) {
738 g_application_activate (app);
739 }
740
741 /* set song rating */
742 if (set_rating >= 0.0 && set_rating <= 5.0) {
743 rb_debug ("rate song");
744
745 rate_song (mpris, set_rating);
746 }
747
748 /* skip to next or previous track */
749 if (next) {
750 rb_debug ("next track");
751 g_dbus_proxy_call_sync (mpris, "Next", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
752 annoy (&error);
753 } else if (previous) {
754 rb_debug ("previous track");
755 g_dbus_proxy_call_sync (mpris, "Previous", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
756 annoy (&error);
757 }
758
759 /* seek in track */
760 if (seek != 0) {
761 GHashTable *properties;
762 rb_debug ("seek");
763
764 properties = get_playing_song_info (mpris);
765 if (properties != NULL) {
766 GVariant *v = g_hash_table_lookup (properties, "mpris:trackid");
767 if (v != NULL) {
768 g_dbus_proxy_call_sync (mpris,
769 "SetPosition",
770 g_variant_new ("(ox)", g_variant_get_string (v, NULL), seek),
771 G_DBUS_CALL_FLAGS_NONE,
772 -1,
773 NULL,
774 &error);
775 annoy (&error);
776 }
777 }
778 }
779
780 /* add/enqueue */
781 if (clear_queue) {
782 g_dbus_proxy_call_sync (queue, "ClearQueue", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
783 annoy (&error);
784 }
785 if (other_stuff) {
786 int i;
787 for (i = 0; other_stuff[i] != NULL; i++) {
788 GFile *file;
789 char *fileuri;
790
791 file = g_file_new_for_commandline_arg (other_stuff[i]);
792 fileuri = g_file_get_uri (file);
793 if (fileuri == NULL) {
794 g_warning ("couldn't convert \"%s\" to a URI", other_stuff[i]);
795 continue;
796 }
797
798 if (enqueue) {
799 rb_debug ("enqueueing %s", fileuri);
800 g_dbus_proxy_call_sync (queue, "AddToQueue", g_variant_new ("(s)", fileuri), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
801 annoy (&error);
802 } else {
803 rb_debug ("importing %s", fileuri);
804 g_action_group_activate_action (G_ACTION_GROUP (app), "LoadURI", g_variant_new ("(sb)", fileuri, FALSE));
805 }
806 g_free (fileuri);
807 g_object_unref (file);
808 }
809 }
810
811 /* select/activate/play source */
812 if (select_source) {
813 rb_debug ("selecting source %s", select_source);
814 g_action_group_activate_action (G_ACTION_GROUP (app), "ActivateSource", g_variant_new ("(su)", select_source, 0));
815 } else if (activate_source) {
816 rb_debug ("activating source %s", activate_source);
817 g_action_group_activate_action (G_ACTION_GROUP (app), "ActivateSource", g_variant_new ("(su)", activate_source, 1));
818 } else if (play_source) {
819 rb_debug ("playing source %s", play_source);
820 g_action_group_activate_action (G_ACTION_GROUP (app), "ActivateSource", g_variant_new ("(su)", play_source, 2));
821 }
822
823 /* play uri */
824 if (play_uri) {
825 GFile *file;
826 char *fileuri;
827
828 file = g_file_new_for_commandline_arg (play_uri);
829 fileuri = g_file_get_uri (file);
830 if (fileuri == NULL) {
831 g_warning ("couldn't convert \"%s\" to a URI", play_uri);
832 } else {
833 rb_debug ("loading and playing %s", fileuri);
834 g_action_group_activate_action (G_ACTION_GROUP (app), "LoadURI", g_variant_new ("(sb)", fileuri, TRUE));
835 annoy (&error);
836 }
837 g_free (fileuri);
838 g_object_unref (file);
839 }
840
841 /* play/pause/stop */
842 if (mpris) {
843 GVariant *v;
844 gboolean is_playing = FALSE;
845
846 v = g_dbus_proxy_get_cached_property (mpris, "PlaybackStatus");
847 if (v != NULL) {
848 is_playing = (g_strcmp0 (g_variant_get_string (v, NULL), "Playing") == 0);
849 g_variant_unref (v);
850 }
851
852 if (play || do_pause || play_pause) {
853 if (is_playing != play || play_pause) {
854 rb_debug ("calling PlayPause to change playback state");
855 g_dbus_proxy_call_sync (mpris, "PlayPause", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
856 annoy (&error);
857 } else {
858 rb_debug ("no need to change playback state");
859 }
860 } else if (stop) {
861 g_warning ("not implemented yet");
862 }
863 }
864
865 /* get/set volume, mute/unmute */
866 if (set_volume > -0.01) {
867 g_dbus_proxy_call_sync (mpris,
868 "org.freedesktop.DBus.Properties.Set",
869 g_variant_new ("(ssv)", "org.mpris.MediaPlayer2.Player", "Volume", g_variant_new_double (set_volume)),
870 G_DBUS_CALL_FLAGS_NONE,
871 -1,
872 NULL,
873 &error);
874 annoy (&error);
875 } else if (volume_up || volume_down) {
876 GVariant *v;
877
878 v = g_dbus_proxy_get_cached_property (mpris, "Volume");
879 if (v != NULL) {
880
881 set_volume = g_variant_get_double (v) + (volume_up ? 0.1 : -0.1);
882 g_dbus_proxy_call_sync (mpris,
883 "org.freedesktop.DBus.Properties.Set",
884 g_variant_new ("(ssv)", "org.mpris.MediaPlayer2.Player", "Volume", g_variant_new_double (set_volume)),
885 G_DBUS_CALL_FLAGS_NONE,
886 -1,
887 NULL,
888 &error);
889 annoy (&error);
890
891 g_variant_unref (v);
892 }
893 }
894 /* no mute for now? */
895 /*
896 } else if (unmute || mute) {
897 org_gnome_Rhythmbox_Player_set_mute (player_proxy, unmute ? FALSE : TRUE, &error);
898 annoy (&error);
899 }
900 */
901
902 if (print_volume) {
903 gdouble volume = 1.0;
904 GVariant *v = g_dbus_proxy_get_cached_property (mpris, "Volume");
905 if (v != NULL) {
906 volume = g_variant_get_double (v);
907 g_variant_unref (v);
908 }
909 g_print (_("Playback volume is %f.\n"), volume);
910 }
911
912 /* print playing song */
913 if (print_playing_format) {
914 print_playing_song (mpris, print_playing_format);
915 } else if (print_playing) {
916 print_playing_song_default (mpris);
917 }
918
919 if (mpris) {
920 g_object_unref (mpris);
921 }
922
923 g_dbus_connection_flush_sync (bus, NULL, NULL);
924 g_option_context_free (context);
925
926 return 0;
927 }