Пример #1
0
static void position_hook (void * data, void * list)
{
    if (aud_playlist_update_pending ())
        position_changed = TRUE;
    else
        audgui_list_set_highlight (list, aud_playlist_get_playing ());
}
Пример #2
0
static void ready (void *hook_data, void *user_data) {
    cleanup_current_track();

    Tuple *current_track = aud_playlist_entry_get_tuple(aud_playlist_get_playing(), aud_playlist_get_position(aud_playlist_get_playing()), FALSE);

    int duration_seconds = tuple_get_int(current_track, FIELD_LENGTH) / 1000;
    if (duration_seconds <= 30) {
        tuple_unref(current_track);
        return;
    }

    pthread_mutex_lock(&communication_mutex);
    now_playing_track = tuple_ref(current_track);
    now_playing_requested = TRUE;
    pthread_cond_signal(&communication_signal);
    pthread_mutex_unlock(&communication_mutex);

    time_until_scrobble = (((gint64)duration_seconds)*G_USEC_PER_SEC) / 2;
    if (time_until_scrobble > 4*60*G_USEC_PER_SEC) {
        time_until_scrobble = 4*60*G_USEC_PER_SEC;
    }
    timestamp = g_get_real_time() / G_USEC_PER_SEC;
    play_started_at = g_get_monotonic_time();
    playing_track = current_track;

    queue_function_ID = g_timeout_add_seconds(time_until_scrobble / G_USEC_PER_SEC, (GSourceFunc) queue_track_to_scrobble, NULL);

}
Пример #3
0
static void update_hook (void * data, void * list)
{
    int rows = aud_playlist_count ();

    if (GPOINTER_TO_INT (data) == PLAYLIST_UPDATE_STRUCTURE)
    {
        int old_rows = audgui_list_row_count (list);

        if (rows < old_rows)
            audgui_list_delete_rows (list, rows, old_rows - rows);
        else if (rows > old_rows)
            audgui_list_insert_rows (list, old_rows, rows - old_rows);

        position_changed = TRUE;
        playlist_activated = TRUE;
    }

    if (GPOINTER_TO_INT (data) >= PLAYLIST_UPDATE_METADATA)
        audgui_list_update_rows (list, 0, rows);

    if (playlist_activated)
    {
        audgui_list_set_focus (list, aud_playlist_get_active ());
        audgui_list_update_selection (list, 0, rows);
        playlist_activated = FALSE;
    }

    if (position_changed)
    {
        audgui_list_set_highlight (list, aud_playlist_get_playing ());
        position_changed = FALSE;
    }
}
Пример #4
0
void
equalizerwin_create(void)
{
    equalizer_presets = aud_equalizer_read_presets("eq.preset");
    equalizer_auto_presets = aud_equalizer_read_presets("eq.auto_preset");

    if (! equalizer_presets)
        equalizer_presets = index_new ();
    if (! equalizer_auto_presets)
        equalizer_auto_presets = index_new ();

    equalizerwin_create_window();

    gtk_window_add_accel_group( GTK_WINDOW(equalizerwin) , ui_manager_get_accel_group() );

    equalizerwin_create_widgets();
    window_show_all (equalizerwin);

    g_signal_connect (equalizerwin, "destroy", (GCallback) equalizerwin_destroyed, NULL);

    hook_associate ("set equalizer_active", (HookFunction) update_from_config, NULL);
    hook_associate ("set equalizer_bands", (HookFunction) update_from_config, NULL);
    hook_associate ("set equalizer_preamp", (HookFunction) update_from_config, NULL);

    int playlist = aud_playlist_get_playing ();

    /* Load preset for the first song. FIXME: Doing this at interface load is
     really too late as the song may already be started. Really, this stuff
     shouldn't be in the interface plugin at all but in core. -jlindgren */
    if (playlist != -1)
        position_cb (GINT_TO_POINTER (playlist), NULL);

    hook_associate ("playlist position", position_cb, NULL);
}
Пример #5
0
static void ui_infoarea_set_title (void)
{
    g_return_if_fail (area);

    if (! aud_drct_get_playing ())
        return;

    int playlist = aud_playlist_get_playing ();
    int entry = aud_playlist_get_position (playlist);

    char * title, * artist, * album;
    aud_playlist_entry_describe (playlist, entry, & title, & artist, & album, TRUE);

    if (! g_strcmp0 (title, area->title) && ! g_strcmp0 (artist, area->artist)
     && ! g_strcmp0 (album, area->album))
    {
        str_unref (title);
        str_unref (artist);
        str_unref (album);
        return;
    }

    str_unref (area->title);
    str_unref (area->artist);
    str_unref (area->album);
    area->title = title;
    area->artist = artist;
    area->album = album;

    gtk_widget_queue_draw (area->main);
}
Пример #6
0
static GtkWidget * create_playlist_manager (void)
{
    GtkWidget * playman_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_type_hint ((GtkWindow *) playman_win, GDK_WINDOW_TYPE_HINT_DIALOG);
    gtk_window_set_title ((GtkWindow *) playman_win, _("Playlist Manager"));
    gtk_container_set_border_width ((GtkContainer *) playman_win, 6);
    gtk_widget_set_size_request (playman_win, 400, 250);

    g_signal_connect (playman_win, "destroy", (GCallback) destroy_cb, NULL);
    audgui_destroy_on_escape (playman_win);

    GtkWidget * playman_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
    gtk_container_add ((GtkContainer *) playman_win, playman_vbox);

    /* ListView */
    GtkWidget * playman_pl_lv = audgui_list_new (& callbacks, NULL, aud_playlist_count ());
    audgui_list_add_column (playman_pl_lv, _("Title"), 0, G_TYPE_STRING, -1);
    audgui_list_add_column (playman_pl_lv, _("Entries"), 1, G_TYPE_INT, 7);
    audgui_list_set_highlight (playman_pl_lv, aud_playlist_get_playing ());
    gtk_tree_view_set_search_equal_func ((GtkTreeView *) playman_pl_lv,
     search_cb, NULL, NULL);
    hook_associate ("playlist update", update_hook, playman_pl_lv);
    hook_associate ("playlist activate", activate_hook, playman_pl_lv);
    hook_associate ("playlist set playing", position_hook, playman_pl_lv);

    GtkWidget * playman_pl_lv_sw = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) playman_pl_lv_sw,
     GTK_SHADOW_IN);
    gtk_scrolled_window_set_policy ((GtkScrolledWindow *) playman_pl_lv_sw,
     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_container_add ((GtkContainer *) playman_pl_lv_sw, playman_pl_lv);
    gtk_box_pack_start ((GtkBox *) playman_vbox, playman_pl_lv_sw, TRUE, TRUE, 0);

    /* ButtonBox */
    GtkWidget * playman_button_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    GtkWidget * new_button = audgui_button_new (_("_New"), "document-new", new_cb, NULL);
    GtkWidget * delete_button = audgui_button_new (_("_Remove"), "edit-delete", delete_cb, NULL);
    GtkWidget * rename_button = audgui_button_new (_("Ren_ame"), "insert-text", rename_cb, NULL);
    GtkWidget * play_button = audgui_button_new (_("_Play"), "media-playback-start", play_cb, NULL);

    gtk_container_add ((GtkContainer *) playman_button_hbox, new_button);
    gtk_container_add ((GtkContainer *) playman_button_hbox, delete_button);
    gtk_box_pack_end ((GtkBox *) playman_button_hbox, play_button, FALSE, FALSE, 0);
    gtk_box_pack_end ((GtkBox *) playman_button_hbox, rename_button, FALSE, FALSE, 0);
    gtk_container_add ((GtkContainer *) playman_vbox, playman_button_hbox);

    /* CheckButton */
    GtkWidget * hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    gtk_box_pack_start ((GtkBox *) playman_vbox, hbox, FALSE, FALSE, 0);
    GtkWidget * check_button = gtk_check_button_new_with_mnemonic
     (_("_Close dialog on activating playlist"));
    gtk_box_pack_start ((GtkBox *) hbox, check_button, FALSE, FALSE, 0);
    gtk_toggle_button_set_active ((GtkToggleButton *) check_button, aud_get_bool
     ("audgui", "playlist_manager_close_on_activate"));
    g_signal_connect (check_button, "toggled", (GCallback) close_on_activate_cb, NULL);

    return playman_win;
}
Пример #7
0
static void position_cb (void * data, void * user_data)
{
    gint playlist = GPOINTER_TO_INT (data);
    gint position = aud_playlist_get_position (playlist);

    if (! aud_get_bool (NULL, "equalizer_autoload") || playlist !=
            aud_playlist_get_playing () || position == -1)
        return;

    gchar * filename = aud_playlist_entry_get_filename (playlist, position);
    load_auto_preset (filename);
    str_unref (filename);
}
Пример #8
0
EXPORT GdkPixbuf * audgui_pixbuf_for_current (void)
{
    if (! current_pixbuf)
    {
        int list = aud_playlist_get_playing ();
        current_pixbuf = audgui_pixbuf_for_entry (list, aud_playlist_get_position (list));
    }

    if (current_pixbuf)
        g_object_ref ((GObject *) current_pixbuf);

    return current_pixbuf;
}
Пример #9
0
void audgui_infowin_show_current (void)
{
    int playlist = aud_playlist_get_playing ();
    int position;

    if (playlist == -1)
        playlist = aud_playlist_get_active ();

    position = aud_playlist_get_position (playlist);

    if (position == -1)
        return;

    audgui_infowin_show (playlist, position);
}
static void set_tab_label (gint list, GtkLabel * label)
{
    gchar * title = aud_playlist_get_title (list);

    if (list == aud_playlist_get_playing ())
    {
        gchar * markup = g_markup_printf_escaped ("<b>%s</b>", title);
        gtk_label_set_markup (label, markup);
        g_free (markup);
    }
    else
        gtk_label_set_text (label, title);

    str_unref (title);
}
Пример #11
0
EXPORT GdkPixbuf * audgui_pixbuf_request_current (void)
{
    if (! current_pixbuf)
    {
        int list = aud_playlist_get_playing ();
        int entry = aud_playlist_get_position (list);
        if (entry < 0)
            return NULL;

        char * filename = aud_playlist_entry_get_filename (list, entry);
        current_pixbuf = audgui_pixbuf_request (filename);
        str_unref (filename);
    }

    if (current_pixbuf)
        g_object_ref ((GObject *) current_pixbuf);

    return current_pixbuf;
}
Пример #12
0
static void lyricwiki_playback_began(void)
{
	if (!aud_drct_get_playing())
		return;

	/* FIXME: cancel previous VFS requests (not possible with current API) */
	str_unref(state.filename);
	str_unref(state.title);
	str_unref(state.artist);
	str_unref(state.uri);

	int playlist = aud_playlist_get_playing();
	int pos = aud_playlist_get_position(playlist);

	state.filename = aud_playlist_entry_get_filename(playlist, pos);
	aud_playlist_entry_describe(playlist, pos, &state.title, &state.artist, NULL, FALSE);
	state.uri = NULL;

	get_lyrics_step_1();
}
void ui_playlist_notebook_populate(void)
{
    gint playlists = aud_playlist_count();
    gint count;

    for (count = 0; count < playlists; count++)
        ui_playlist_notebook_create_tab(count);

    gtk_notebook_set_current_page (UI_PLAYLIST_NOTEBOOK, aud_playlist_get_active ());
    highlighted = aud_playlist_get_unique_id (aud_playlist_get_playing ());

    if (! switch_handler)
        switch_handler = g_signal_connect (notebook, "switch-page", (GCallback)
         tab_changed, NULL);
    if (! reorder_handler)
        reorder_handler = g_signal_connect (notebook, "page-reordered",
         (GCallback) tab_reordered, NULL);

    gtk_widget_grab_focus (playlist_get_treeview (aud_playlist_get_active ()));
}
Пример #14
0
static gint file_open(gint fmt, gint rate, gint nch)
{
    gchar *filename = NULL, *temp = NULL;
    gchar * directory;
    gint pos;
    gint rv;
    gint playlist;

    input.format = fmt;
    input.frequency = rate;
    input.channels = nch;

    playlist = aud_playlist_get_playing ();
    if (playlist < 0)
        return 0;

    pos = aud_playlist_get_position(playlist);
    tuple = aud_playlist_entry_get_tuple (playlist, pos, FALSE);
    if (tuple == NULL)
        return 0;

    if (filenamefromtags)
    {
        gchar * utf8 = aud_playlist_entry_get_title (playlist, pos, FALSE);
        string_replace_char (utf8, '/', ' ');

        gchar buf[3 * strlen (utf8) + 1];
        str_encode_percent (utf8, -1, buf);
        str_unref (utf8);

        filename = g_strdup (buf);
    }
    else
    {
        temp = aud_playlist_entry_get_filename (playlist, pos);
        gchar * original = strrchr (temp, '/');
        g_return_val_if_fail (original != NULL, 0);
        filename = g_strdup (original + 1);
        str_unref (temp);

        if (!use_suffix)
            if ((temp = strrchr(filename, '.')) != NULL)
                *temp = '\0';
    }

    if (prependnumber)
    {
        gint number = tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL);
        if (!tuple || !number)
            number = pos + 1;

        temp = g_strdup_printf ("%d%%20%s", number, filename);
        g_free(filename);
        filename = temp;
    }

    if (save_original)
    {
        temp = aud_playlist_entry_get_filename (playlist, pos);
        directory = g_strdup (temp);
        str_unref (temp);
        temp = strrchr (directory, '/');
        g_return_val_if_fail (temp != NULL, 0);
        temp[1] = 0;
    }
    else
    {
        g_return_val_if_fail (file_path[0], 0);
        if (file_path[strlen (file_path) - 1] == '/')
            directory = g_strdup (file_path);
        else
            directory = g_strdup_printf ("%s/", file_path);
    }

    temp = g_strdup_printf ("%s%s.%s", directory, filename, fileext_str[fileext]);
    g_free (directory);
    g_free (filename);
    filename = temp;

    output_file = safe_create (filename);
    g_free (filename);

    if (output_file == NULL)
        return 0;

    convert_init (fmt, plugin->format_required (fmt), nch);

    rv = (plugin->open)();

    samples_written = 0;

    return rv;
}
Пример #15
0
/* do_command(): do @cmd after replacing the format codes
   @cmd: command to run */
static void do_command (char * cmd)
{
    int playlist = aud_playlist_get_playing ();
    int pos = aud_playlist_get_position (playlist);

    char *shstring = NULL, *temp, numbuf[32];
    gboolean playing;
    Formatter *formatter;

    if (cmd && strlen(cmd) > 0)
    {
        formatter = formatter_new();

        char * ctitle = aud_playlist_entry_get_title (playlist, pos, FALSE);
        if (ctitle)
        {
            temp = escape_shell_chars (ctitle);
            formatter_associate(formatter, 's', temp);
            formatter_associate(formatter, 'n', temp);
            g_free(temp);
            str_unref (ctitle);
        }
        else
        {
            formatter_associate(formatter, 's', "");
            formatter_associate(formatter, 'n', "");
        }

        char * filename = aud_playlist_entry_get_filename (playlist, pos);
        if (filename)
        {
            temp = escape_shell_chars (filename);
            formatter_associate(formatter, 'f', temp);
            g_free(temp);
            str_unref (filename);
        }
        else
            formatter_associate(formatter, 'f', "");

        g_snprintf(numbuf, sizeof(numbuf), "%02d", pos + 1);
        formatter_associate(formatter, 't', numbuf);

        int length = aud_playlist_entry_get_length (playlist, pos, FALSE);
        if (length > 0)
        {
            g_snprintf(numbuf, sizeof(numbuf), "%d", length);
            formatter_associate(formatter, 'l', numbuf);
        }
        else
            formatter_associate(formatter, 'l', "0");

        playing = aud_drct_get_playing();
        g_snprintf(numbuf, sizeof(numbuf), "%d", playing);
        formatter_associate(formatter, 'p', numbuf);

        if (playing)
        {
            int brate, srate, chans;
            aud_drct_get_info (& brate, & srate, & chans);
            snprintf (numbuf, sizeof numbuf, "%d", brate);
            formatter_associate (formatter, 'r', numbuf);
            snprintf (numbuf, sizeof numbuf, "%d", srate);
            formatter_associate (formatter, 'F', numbuf);
            snprintf (numbuf, sizeof numbuf, "%d", chans);
            formatter_associate (formatter, 'c', numbuf);
        }

        Tuple * tuple = aud_playlist_entry_get_tuple
            (aud_playlist_get_active (), pos, 0);

        char * artist = tuple ? tuple_get_str (tuple, FIELD_ARTIST, NULL) : NULL;
        if (artist)
        {
            formatter_associate(formatter, 'a', artist);
            str_unref(artist);
        }
        else
            formatter_associate(formatter, 'a', "");

        char * album = tuple ? tuple_get_str (tuple, FIELD_ALBUM, NULL) : NULL;
        if (album)
        {
            formatter_associate(formatter, 'b', album);
            str_unref(album);
        }
        else
            formatter_associate(formatter, 'b', "");

        char * title = tuple ? tuple_get_str (tuple, FIELD_TITLE, NULL) : NULL;
        if (title)
        {
            formatter_associate(formatter, 'T', title);
            str_unref(title);
        }
        else
            formatter_associate(formatter, 'T', "");

        if (tuple)
            tuple_unref (tuple);

        shstring = formatter_format(formatter, cmd);
        formatter_destroy(formatter);

        if (shstring)
        {
            execute_command(shstring);
            /* FIXME: This can possibly be freed too early */
            g_free(shstring);
        }
    }
}
Пример #16
0
EXPORT void audgui_playlist_manager (void)
{
    GtkWidget * playman_vbox;
    GtkWidget * playman_pl_lv, * playman_pl_lv_sw;
    GtkWidget * playman_button_hbox;
    GtkWidget * new_button, * delete_button, * rename_button, * play_button;
    GtkWidget * hbox, * check_button;
    GdkGeometry playman_win_hints;

    if (playman_win)
    {
        gtk_window_present ((GtkWindow *) playman_win);
        return;
    }

    playman_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_type_hint ((GtkWindow *) playman_win, GDK_WINDOW_TYPE_HINT_DIALOG);
    gtk_window_set_title ((GtkWindow *) playman_win, _("Playlist Manager"));
    gtk_container_set_border_width ((GtkContainer *) playman_win, 6);
    playman_win_hints.min_width = 400;
    playman_win_hints.min_height = 250;
    gtk_window_set_geometry_hints ((GtkWindow *) playman_win, playman_win,
                                   &playman_win_hints , GDK_HINT_MIN_SIZE);

    int x = aud_get_int ("audgui", "playlist_manager_x");
    int y = aud_get_int ("audgui", "playlist_manager_y");
    int w = aud_get_int ("audgui", "playlist_manager_w");
    int h = aud_get_int ("audgui", "playlist_manager_h");

    if (w && h)
    {
        gtk_window_move ((GtkWindow *) playman_win, x, y);
        gtk_window_set_default_size ((GtkWindow *) playman_win, w, h);
    }

    g_signal_connect (playman_win, "delete-event", (GCallback) hide_cb, NULL);
    audgui_hide_on_escape (playman_win);

    playman_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
    gtk_container_add ((GtkContainer *) playman_win, playman_vbox);

    /* ListView */
    playman_pl_lv = audgui_list_new (& callbacks, NULL, aud_playlist_count ());
    audgui_list_add_column (playman_pl_lv, _("Title"), 0, G_TYPE_STRING, -1);
    audgui_list_add_column (playman_pl_lv, _("Entries"), 1, G_TYPE_INT, 7);
    audgui_list_set_highlight (playman_pl_lv, aud_playlist_get_playing ());
    gtk_tree_view_set_search_equal_func ((GtkTreeView *) playman_pl_lv,
     search_cb, NULL, NULL);
    hook_associate ("playlist update", update_hook, playman_pl_lv);
    hook_associate ("playlist activate", activate_hook, playman_pl_lv);
    hook_associate ("playlist set playing", position_hook, playman_pl_lv);

    playman_pl_lv_sw = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) playman_pl_lv_sw,
     GTK_SHADOW_IN);
    gtk_scrolled_window_set_policy ((GtkScrolledWindow *) playman_pl_lv_sw,
     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_container_add ((GtkContainer *) playman_pl_lv_sw, playman_pl_lv);
    gtk_box_pack_start ((GtkBox *) playman_vbox, playman_pl_lv_sw, TRUE, TRUE, 0);

    /* ButtonBox */
    playman_button_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    new_button = gtk_button_new_from_stock (GTK_STOCK_NEW);
    delete_button = gtk_button_new_from_stock (GTK_STOCK_DELETE);
    rename_button = gtk_button_new_with_mnemonic (_("_Rename"));
    gtk_button_set_image ((GtkButton *) rename_button, gtk_image_new_from_stock
     (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON));
    play_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);

    gtk_container_add ((GtkContainer *) playman_button_hbox, new_button);
    gtk_container_add ((GtkContainer *) playman_button_hbox, delete_button);
    gtk_box_pack_end ((GtkBox *) playman_button_hbox, play_button, FALSE, FALSE, 0);
    gtk_box_pack_end ((GtkBox *) playman_button_hbox, rename_button, FALSE, FALSE, 0);
    gtk_container_add ((GtkContainer *) playman_vbox, playman_button_hbox);

    g_signal_connect (new_button, "clicked", (GCallback) new_cb, NULL);
    g_signal_connect (delete_button, "clicked", (GCallback) delete_cb, NULL);
    g_signal_connect (rename_button, "clicked", (GCallback) rename_cb, NULL);
    g_signal_connect (play_button, "clicked", (GCallback) play_cb, NULL);

    /* CheckButton */
    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    gtk_box_pack_start ((GtkBox *) playman_vbox, hbox, FALSE, FALSE, 0);
    check_button = gtk_check_button_new_with_mnemonic
     (_("_Close dialog on activating playlist"));
    gtk_box_pack_start ((GtkBox *) hbox, check_button, FALSE, FALSE, 0);
    gtk_toggle_button_set_active ((GtkToggleButton *) check_button, aud_get_bool
     ("audgui", "playlist_manager_close_on_activate"));
    g_signal_connect (check_button, "toggled", (GCallback) close_on_activate_cb, NULL);

    gtk_widget_show_all (playman_win);

    hook_associate ("config save", save_config_cb, playman_win);
}
Пример #17
0
static void update_metadata (void * data, GObject * object)
{
    char * title = NULL, * artist = NULL, * album = NULL, * file = NULL;
    int length = 0;

    int playlist = aud_playlist_get_playing ();
    int entry = (playlist >= 0) ? aud_playlist_get_position (playlist) : -1;

    if (entry >= 0)
    {
        aud_playlist_entry_describe (playlist, entry, & title, & artist, & album, TRUE);
        file = aud_playlist_entry_get_filename (playlist, entry);
        length = aud_playlist_entry_get_length (playlist, entry, TRUE);
    }

    /* pointer comparison works for pooled strings */
    if (title == last_title && artist == last_artist && album == last_album &&
     file == last_file && length == last_length)
    {
        str_unref (title);
        str_unref (artist);
        str_unref (album);
        str_unref (file);
        return;
    }

    if (file != last_file)
    {
        if (image_file)
            aud_art_unref (last_file);
        image_file = file ? aud_art_get_file (file) : NULL;
    }

    str_unref (last_title);
    str_unref (last_artist);
    str_unref (last_album);
    str_unref (last_file);
    last_title = title;
    last_artist = artist;
    last_album = album;
    last_file = file;
    last_length = length;

    GVariant * elems[7];
    int nelems = 0;

    if (title)
    {
        GVariant * key = g_variant_new_string ("xesam:title");
        GVariant * str = g_variant_new_string (title);
        GVariant * var = g_variant_new_variant (str);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    if (artist)
    {
        GVariant * key = g_variant_new_string ("xesam:artist");
        GVariant * str = g_variant_new_string (artist);
        GVariant * array = g_variant_new_array (G_VARIANT_TYPE_STRING, & str, 1);
        GVariant * var = g_variant_new_variant (array);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    if (album)
    {
        GVariant * key = g_variant_new_string ("xesam:album");
        GVariant * str = g_variant_new_string (album);
        GVariant * var = g_variant_new_variant (str);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    if (file)
    {
        GVariant * key = g_variant_new_string ("xesam:url");
        GVariant * str = g_variant_new_string (file);
        GVariant * var = g_variant_new_variant (str);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    if (length > 0)
    {
        GVariant * key = g_variant_new_string ("mpris:length");
        GVariant * val = g_variant_new_int64 ((int64_t) length * 1000);
        GVariant * var = g_variant_new_variant (val);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    if (image_file)
    {
        GVariant * key = g_variant_new_string ("mpris:artUrl");
        GVariant * str = g_variant_new_string (image_file);
        GVariant * var = g_variant_new_variant (str);
        elems[nelems ++] = g_variant_new_dict_entry (key, var);
    }

    GVariant * key = g_variant_new_string ("mpris:trackid");
    GVariant * str = g_variant_new_string ("/org/mpris/MediaPlayer2/CurrentTrack");
    GVariant * var = g_variant_new_variant (str);
    elems[nelems ++] = g_variant_new_dict_entry (key, var);

    if (! metadata_type)
        metadata_type = g_variant_type_new ("{sv}");

    GVariant * array = g_variant_new_array (metadata_type, elems, nelems);
    g_object_set (object, "metadata", array, NULL);
}