Code

mpdclient: mpdclient_disconnect() returns void
[ncmpc.git] / src / mpdclient.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2009 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
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 of the License, or
8  * (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
20 #include "mpdclient.h"
21 #include "filelist.h"
22 #include "screen_client.h"
23 #include "config.h"
24 #include "options.h"
25 #include "strfsong.h"
26 #include "utils.h"
28 #include <mpd/client.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <string.h>
35 #undef  ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD /* broken with song id's */
36 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
37 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
39 #define BUFSIZE 1024
41 static bool
42 MPD_ERROR(const struct mpdclient *client)
43 {
44         return client->connection == NULL ||
45                 mpd_connection_get_error(client->connection) != MPD_ERROR_SUCCESS;
46 }
48 /* filelist sorting functions */
49 static gint
50 compare_filelistentry(gconstpointer filelist_entry1,
51                           gconstpointer filelist_entry2)
52 {
53         const struct mpd_entity *e1, *e2;
54         int n = 0;
56         e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
57         e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
59         if (e1 != NULL && e2 != NULL &&
60             mpd_entity_get_type(e1) == mpd_entity_get_type(e2)) {
61                 switch (mpd_entity_get_type(e1)) {
62                 case MPD_ENTITY_TYPE_UNKNOWN:
63                         break;
64                 case MPD_ENTITY_TYPE_DIRECTORY:
65                         n = g_utf8_collate(mpd_directory_get_path(mpd_entity_get_directory(e1)),
66                                            mpd_directory_get_path(mpd_entity_get_directory(e2)));
67                         break;
68                 case MPD_ENTITY_TYPE_SONG:
69                         break;
70                 case MPD_ENTITY_TYPE_PLAYLIST:
71                         n = g_utf8_collate(mpd_playlist_get_path(mpd_entity_get_playlist(e1)),
72                                            mpd_playlist_get_path(mpd_entity_get_playlist(e2)));
73                 }
74         }
75         return n;
76 }
78 /* sort by list-format */
79 gint
80 compare_filelistentry_format(gconstpointer filelist_entry1,
81                              gconstpointer filelist_entry2)
82 {
83         const struct mpd_entity *e1, *e2;
84         char key1[BUFSIZE], key2[BUFSIZE];
85         int n = 0;
87         e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
88         e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
90         if (e1 && e2 &&
91             mpd_entity_get_type(e1) == MPD_ENTITY_TYPE_SONG &&
92             mpd_entity_get_type(e2) == MPD_ENTITY_TYPE_SONG) {
93                 strfsong(key1, BUFSIZE, options.list_format, mpd_entity_get_song(e1));
94                 strfsong(key2, BUFSIZE, options.list_format, mpd_entity_get_song(e2));
95                 n = strcmp(key1,key2);
96         }
98         return n;
99 }
102 /****************************************************************************/
103 /*** mpdclient functions ****************************************************/
104 /****************************************************************************/
106 gint
107 mpdclient_handle_error(struct mpdclient *c)
109         enum mpd_error error = mpd_connection_get_error(c->connection);
111         assert(error != MPD_ERROR_SUCCESS);
113         if (error == MPD_ERROR_SERVER &&
114             mpd_connection_get_server_error(c->connection) == MPD_SERVER_ERROR_PERMISSION &&
115             screen_auth(c))
116                 return 0;
118         if (error == MPD_ERROR_SERVER)
119                 error = error | (mpd_connection_get_server_error(c->connection) << 8);
121         for (GList *list = c->error_callbacks; list != NULL;
122              list = list->next) {
123                 mpdc_error_cb_t cb = list->data;
124                 cb(c, error, mpd_connection_get_error_message(c->connection));
125         }
127         if (!mpd_connection_clear_error(c->connection))
128                 mpdclient_disconnect(c);
130         return error;
133 static gint
134 mpdclient_finish_command(struct mpdclient *c)
136         return mpd_response_finish(c->connection)
137                 ? 0 : mpdclient_handle_error(c);
140 struct mpdclient *
141 mpdclient_new(void)
143         struct mpdclient *c;
145         c = g_new0(struct mpdclient, 1);
146         playlist_init(&c->playlist);
147         c->volume = MPD_STATUS_NO_VOLUME;
149         return c;
152 void
153 mpdclient_free(struct mpdclient *c)
155         mpdclient_disconnect(c);
157         mpdclient_playlist_free(&c->playlist);
159         g_list_free(c->error_callbacks);
160         g_list_free(c->playlist_callbacks);
161         g_list_free(c->browse_callbacks);
162         g_free(c);
165 void
166 mpdclient_disconnect(struct mpdclient *c)
168         if (c->connection)
169                 mpd_connection_free(c->connection);
170         c->connection = NULL;
172         if (c->status)
173                 mpd_status_free(c->status);
174         c->status = NULL;
176         playlist_clear(&c->playlist);
178         if (c->song)
179                 c->song = NULL;
182 gint
183 mpdclient_connect(struct mpdclient *c,
184                   const gchar *host,
185                   gint port,
186                   gfloat _timeout,
187                   const gchar *password)
189         gint retval = 0;
191         /* close any open connection */
192         if( c->connection )
193                 mpdclient_disconnect(c);
195         /* connect to MPD */
196         c->connection = mpd_connection_new(host, port, _timeout * 1000);
197         if (c->connection == NULL)
198                 g_error("Out of memory");
200         if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) {
201                 retval = mpdclient_handle_error(c);
202                 if (retval != 0) {
203                         mpd_connection_free(c->connection);
204                         c->connection = NULL;
205                 }
207                 return retval;
208         }
210         /* send password */
211         if( password ) {
212                 mpd_send_password(c->connection, password);
213                 retval = mpdclient_finish_command(c);
214         }
216         return retval;
219 gint
220 mpdclient_update(struct mpdclient *c)
222         gint retval = 0;
224         c->volume = MPD_STATUS_NO_VOLUME;
226         if (MPD_ERROR(c))
227                 return -1;
229         /* free the old status */
230         if (c->status)
231                 mpd_status_free(c->status);
233         /* retrieve new status */
234         c->status = mpd_run_status(c->connection);
235         if (c->status == NULL)
236                 return mpdclient_handle_error(c);
238         if (c->updatingdb &&
239             c->updatingdb != mpd_status_get_update_id(c->status))
240                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
242         c->updatingdb = mpd_status_get_update_id(c->status);
243         c->volume = mpd_status_get_volume(c->status);
245         /* check if the playlist needs an update */
246         if (c->playlist.id != mpd_status_get_queue_version(c->status)) {
247                 if (!playlist_is_empty(&c->playlist))
248                         retval = mpdclient_playlist_update_changes(c);
249                 else
250                         retval = mpdclient_playlist_update(c);
251         }
253         /* update the current song */
254         if (!c->song || mpd_status_get_song_id(c->status)) {
255                 c->song = playlist_get_song(&c->playlist,
256                                             mpd_status_get_song_pos(c->status));
257         }
259         return retval;
263 /****************************************************************************/
264 /*** MPD Commands  **********************************************************/
265 /****************************************************************************/
267 gint
268 mpdclient_cmd_play(struct mpdclient *c, gint idx)
270         const struct mpd_song *song = playlist_get_song(&c->playlist, idx);
272         if (MPD_ERROR(c))
273                 return -1;
275         if (song)
276                 mpd_send_play_id(c->connection, mpd_song_get_id(song));
277         else
278                 mpd_send_play(c->connection);
280         return mpdclient_finish_command(c);
283 gint
284 mpdclient_cmd_pause(struct mpdclient *c, gint value)
286         if (MPD_ERROR(c))
287                 return -1;
289         mpd_send_pause(c->connection, value);
290         return mpdclient_finish_command(c);
293 gint
294 mpdclient_cmd_crop(struct mpdclient *c)
296         struct mpd_status *status;
297         bool playing;
298         int length, current;
300         if (MPD_ERROR(c))
301                 return -1;
303         status = mpd_run_status(c->connection);
304         if (status == NULL)
305                 return mpdclient_handle_error(c);
307         playing = mpd_status_get_state(status) == MPD_STATE_PLAY ||
308                 mpd_status_get_state(status) == MPD_STATE_PAUSE;
309         length = mpd_status_get_queue_length(status);
310         current = mpd_status_get_song_pos(status);
312         mpd_status_free(status);
314         if (!playing || length < 2)
315                 return 0;
317         mpd_command_list_begin(c->connection, false);
319         while (--length >= 0)
320                 if (length != current)
321                         mpd_send_delete(c->connection, length);
323         mpd_command_list_end(c->connection);
325         return mpdclient_finish_command(c);
328 gint
329 mpdclient_cmd_stop(struct mpdclient *c)
331         if (MPD_ERROR(c))
332                 return -1;
334         mpd_send_stop(c->connection);
335         return mpdclient_finish_command(c);
338 gint
339 mpdclient_cmd_next(struct mpdclient *c)
341         if (MPD_ERROR(c))
342                 return -1;
344         mpd_send_next(c->connection);
345         return mpdclient_finish_command(c);
348 gint
349 mpdclient_cmd_prev(struct mpdclient *c)
351         if (MPD_ERROR(c))
352                 return -1;
354         mpd_send_previous(c->connection);
355         return mpdclient_finish_command(c);
358 gint
359 mpdclient_cmd_seek(struct mpdclient *c, gint id, gint pos)
361         if (MPD_ERROR(c))
362                 return -1;
364         mpd_send_seek_id(c->connection, id, pos);
365         return mpdclient_finish_command(c);
368 gint
369 mpdclient_cmd_shuffle(struct mpdclient *c)
371         if (MPD_ERROR(c))
372                 return -1;
374         mpd_send_shuffle(c->connection);
375         return mpdclient_finish_command(c);
378 gint
379 mpdclient_cmd_shuffle_range(struct mpdclient *c, guint start, guint end)
381         mpd_send_shuffle_range(c->connection, start, end);
382         return mpdclient_finish_command(c);
385 gint
386 mpdclient_cmd_clear(struct mpdclient *c)
388         gint retval = 0;
390         if (MPD_ERROR(c))
391                 return -1;
393         mpd_send_clear(c->connection);
394         retval = mpdclient_finish_command(c);
395         /* call playlist updated callback */
396         mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
397         return retval;
400 gint
401 mpdclient_cmd_repeat(struct mpdclient *c, gint value)
403         if (MPD_ERROR(c))
404                 return -1;
406         mpd_send_repeat(c->connection, value);
407         return mpdclient_finish_command(c);
410 gint
411 mpdclient_cmd_random(struct mpdclient *c, gint value)
413         if (MPD_ERROR(c))
414                 return -1;
416         mpd_send_random(c->connection, value);
417         return mpdclient_finish_command(c);
420 gint
421 mpdclient_cmd_single(struct mpdclient *c, gint value)
423         if (MPD_ERROR(c))
424                 return -1;
426         mpd_send_single(c->connection, value);
427         return mpdclient_finish_command(c);
430 gint
431 mpdclient_cmd_consume(struct mpdclient *c, gint value)
433         if (MPD_ERROR(c))
434                 return -1;
436         mpd_send_consume(c->connection, value);
437         return mpdclient_finish_command(c);
440 gint
441 mpdclient_cmd_crossfade(struct mpdclient *c, gint value)
443         if (MPD_ERROR(c))
444                 return -1;
446         mpd_send_crossfade(c->connection, value);
447         return mpdclient_finish_command(c);
450 gint
451 mpdclient_cmd_volume(struct mpdclient *c, gint value)
453         if (MPD_ERROR(c))
454                 return -1;
456         mpd_send_set_volume(c->connection, value);
457         return mpdclient_finish_command(c);
460 gint mpdclient_cmd_volume_up(struct mpdclient *c)
462         if (MPD_ERROR(c))
463                 return -1;
465         if (c->status == NULL ||
466             mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME)
467                 return 0;
469         if (c->volume == MPD_STATUS_NO_VOLUME)
470                 c->volume = mpd_status_get_volume(c->status);
472         if (c->volume >= 100)
473                 return 0;
475         return mpdclient_cmd_volume(c, ++c->volume);
478 gint mpdclient_cmd_volume_down(struct mpdclient *c)
480         if (MPD_ERROR(c))
481                 return -1;
483         if (c->status == NULL ||
484             mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME)
485                 return 0;
487         if (c->volume == MPD_STATUS_NO_VOLUME)
488                 c->volume = mpd_status_get_volume(c->status);
490         if (c->volume <= 0)
491                 return 0;
493         return mpdclient_cmd_volume(c, --c->volume);
496 gint
497 mpdclient_cmd_add_path(struct mpdclient *c, const gchar *path_utf8)
499         if (MPD_ERROR(c))
500                 return -1;
502         mpd_send_add(c->connection, path_utf8);
503         return mpdclient_finish_command(c);
506 gint
507 mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song)
509         gint retval = 0;
511         if (MPD_ERROR(c))
512                 return -1;
514         if (song == NULL)
515                 return -1;
517         /* send the add command to mpd */
518         mpd_send_add(c->connection, mpd_song_get_uri(song));
519         if( (retval=mpdclient_finish_command(c)) )
520                 return retval;
522 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
523         /* add the song to playlist */
524         playlist_append(&c->playlist, song);
526         /* increment the playlist id, so we don't retrieve a new playlist */
527         c->playlist.id++;
529         /* call playlist updated callback */
530         mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
531 #endif
533         return 0;
536 gint
537 mpdclient_cmd_delete(struct mpdclient *c, gint idx)
539         gint retval = 0;
540         struct mpd_song *song;
542         if (MPD_ERROR(c))
543                 return -1;
545         if (idx < 0 || (guint)idx >= playlist_length(&c->playlist))
546                 return -1;
548         song = playlist_get(&c->playlist, idx);
550         /* send the delete command to mpd */
551         mpd_send_delete_id(c->connection, mpd_song_get_id(song));
552         if( (retval=mpdclient_finish_command(c)) )
553                 return retval;
555 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
556         /* increment the playlist id, so we don't retrieve a new playlist */
557         c->playlist.id++;
559         /* remove the song from the playlist */
560         playlist_remove_reuse(&c->playlist, idx);
562         /* call playlist updated callback */
563         mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
565         /* remove references to the song */
566         if (c->song == song)
567                 c->song = NULL;
569         mpd_song_free(song);
570 #endif
572         return 0;
575 gint
576 mpdclient_cmd_move(struct mpdclient *c, gint old_index, gint new_index)
578         gint n;
579         struct mpd_song *song1, *song2;
581         if (MPD_ERROR(c))
582                 return -1;
584         if (old_index == new_index || new_index < 0 ||
585             (guint)new_index >= c->playlist.list->len)
586                 return -1;
588         song1 = playlist_get(&c->playlist, old_index);
589         song2 = playlist_get(&c->playlist, new_index);
591         /* send the move command to mpd */
592         mpd_send_swap_id(c->connection,
593                          mpd_song_get_id(song1), mpd_song_get_id(song2));
594         if( (n=mpdclient_finish_command(c)) )
595                 return n;
597 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
598         /* update the playlist */
599         playlist_swap(&c->playlist, old_index, new_index);
601         /* increment the playlist id, so we don't retrieve a new playlist */
602         c->playlist.id++;
603 #endif
605         /* call playlist updated callback */
606         mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
608         return 0;
611 gint
612 mpdclient_cmd_save_playlist(struct mpdclient *c, const gchar *filename_utf8)
614         gint retval = 0;
616         if (MPD_ERROR(c))
617                 return -1;
619         mpd_send_save(c->connection, filename_utf8);
620         if ((retval = mpdclient_finish_command(c)) == 0)
621                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
622         return retval;
625 gint
626 mpdclient_cmd_load_playlist(struct mpdclient *c, const gchar *filename_utf8)
628         if (MPD_ERROR(c))
629                 return -1;
631         mpd_send_load(c->connection, filename_utf8);
632         return mpdclient_finish_command(c);
635 gint
636 mpdclient_cmd_delete_playlist(struct mpdclient *c, const gchar *filename_utf8)
638         gint retval = 0;
640         if (MPD_ERROR(c))
641                 return -1;
643         mpd_send_rm(c->connection, filename_utf8);
644         if ((retval = mpdclient_finish_command(c)) == 0)
645                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
646         return retval;
650 /****************************************************************************/
651 /*** Callback management functions ******************************************/
652 /****************************************************************************/
654 static void
655 do_list_callbacks(struct mpdclient *c, GList *list, gint event, gpointer data)
657         while (list) {
658                 mpdc_list_cb_t fn = list->data;
660                 fn(c, event, data);
661                 list = list->next;
662         }
665 void
666 mpdclient_playlist_callback(struct mpdclient *c, int event, gpointer data)
668         do_list_callbacks(c, c->playlist_callbacks, event, data);
671 void
672 mpdclient_install_playlist_callback(struct mpdclient *c,mpdc_list_cb_t cb)
674         c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
677 void
678 mpdclient_remove_playlist_callback(struct mpdclient *c, mpdc_list_cb_t cb)
680         c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
683 void
684 mpdclient_browse_callback(struct mpdclient *c, int event, gpointer data)
686         do_list_callbacks(c, c->browse_callbacks, event, data);
690 void
691 mpdclient_install_browse_callback(struct mpdclient *c,mpdc_list_cb_t cb)
693         c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
696 void
697 mpdclient_remove_browse_callback(struct mpdclient *c, mpdc_list_cb_t cb)
699         c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
702 void
703 mpdclient_install_error_callback(struct mpdclient *c, mpdc_error_cb_t cb)
705         c->error_callbacks = g_list_append(c->error_callbacks, cb);
708 void
709 mpdclient_remove_error_callback(struct mpdclient *c, mpdc_error_cb_t cb)
711         c->error_callbacks = g_list_remove(c->error_callbacks, cb);
715 /****************************************************************************/
716 /*** Playlist management functions ******************************************/
717 /****************************************************************************/
719 /* update playlist */
720 gint
721 mpdclient_playlist_update(struct mpdclient *c)
723         struct mpd_entity *entity;
725         if (MPD_ERROR(c))
726                 return -1;
728         playlist_clear(&c->playlist);
730         mpd_send_list_queue_meta(c->connection);
731         while ((entity = mpd_recv_entity(c->connection))) {
732                 if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG)
733                         playlist_append(&c->playlist, mpd_entity_get_song(entity));
735                 mpd_entity_free(entity);
736         }
738         c->playlist.id = mpd_status_get_queue_version(c->status);
739         c->song = NULL;
741         /* call playlist updated callbacks */
742         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
744         return mpdclient_finish_command(c);
747 /* update playlist (plchanges) */
748 gint
749 mpdclient_playlist_update_changes(struct mpdclient *c)
751         struct mpd_song *song;
752         guint length;
754         if (MPD_ERROR(c))
755                 return -1;
757         mpd_send_queue_changes_meta(c->connection, c->playlist.id);
759         while ((song = mpd_recv_song(c->connection)) != NULL) {
760                 int pos = mpd_song_get_pos(song);
762                 if (pos >= 0 && (guint)pos < c->playlist.list->len) {
763                         /* update song */
764                         playlist_replace(&c->playlist, pos, song);
765                 } else {
766                         /* add a new song */
767                         playlist_append(&c->playlist, song);
768                 }
770                 mpd_song_free(song);
771         }
773         /* remove trailing songs */
775         length = mpd_status_get_queue_length(c->status);
776         while (length < c->playlist.list->len) {
777                 guint pos = c->playlist.list->len - 1;
779                 /* Remove the last playlist entry */
780                 playlist_remove(&c->playlist, pos);
781         }
783         c->song = NULL;
784         c->playlist.id = mpd_status_get_queue_version(c->status);
786         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
788         return 0;
792 /****************************************************************************/
793 /*** Filelist functions *****************************************************/
794 /****************************************************************************/
796 struct filelist *
797 mpdclient_filelist_get(struct mpdclient *c, const gchar *path)
799         struct filelist *filelist;
800         struct mpd_entity *entity;
802         if (MPD_ERROR(c))
803                 return NULL;
805         mpd_send_list_meta(c->connection, path);
806         filelist = filelist_new();
807         if (path && path[0] && strcmp(path, "/"))
808                 /* add a dummy entry for ./.. */
809                 filelist_append(filelist, NULL);
811         while ((entity = mpd_recv_entity(c->connection)) != NULL)
812                 filelist_append(filelist, entity);
814         /* If there's an error, ignore it.  We'll return an empty filelist. */
815         mpdclient_finish_command(c);
817         filelist_sort_dir_play(filelist, compare_filelistentry);
819         return filelist;
822 static struct filelist *
823 mpdclient_recv_filelist_response(struct mpdclient *c)
825         struct filelist *filelist;
826         struct mpd_entity *entity;
828         filelist = filelist_new();
830         while ((entity = mpd_recv_entity(c->connection)) != NULL)
831                 filelist_append(filelist, entity);
833         if (mpdclient_finish_command(c)) {
834                 filelist_free(filelist);
835                 return NULL;
836         }
838         return filelist;
841 struct filelist *
842 mpdclient_filelist_search(struct mpdclient *c,
843                           int exact_match,
844                           enum mpd_tag_type tag,
845                           gchar *filter_utf8)
847         if (MPD_ERROR(c))
848                 return NULL;
850         mpd_search_db_songs(c->connection, exact_match);
851         mpd_search_add_tag_constraint(c->connection, MPD_OPERATOR_DEFAULT,
852                                       tag, filter_utf8);
853         mpd_search_commit(c->connection);
855         return mpdclient_recv_filelist_response(c);
858 int
859 mpdclient_filelist_add_all(struct mpdclient *c, struct filelist *fl)
861         guint i;
863         if (MPD_ERROR(c))
864                 return -1;
866         if (filelist_is_empty(fl))
867                 return 0;
869         mpd_command_list_begin(c->connection, false);
871         for (i = 0; i < filelist_length(fl); ++i) {
872                 struct filelist_entry *entry = filelist_get(fl, i);
873                 struct mpd_entity *entity  = entry->entity;
875                 if (entity != NULL &&
876                     mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
877                         const struct mpd_song *song =
878                                 mpd_entity_get_song(entity);
879                         const char *uri = mpd_song_get_uri(song);
881                         if (uri != NULL)
882                                 mpd_send_add(c->connection, uri);
883                 }
884         }
886         mpd_command_list_end(c->connection);
887         return mpdclient_finish_command(c);
890 GList *
891 mpdclient_get_artists(struct mpdclient *c)
893         GList *list = NULL;
894         struct mpd_pair *pair;
896         if (MPD_ERROR(c))
897                return NULL;
899         mpd_search_db_tags(c->connection, MPD_TAG_ARTIST);
900         mpd_search_commit(c->connection);
902         while ((pair = mpd_recv_pair_tag(c->connection,
903                                          MPD_TAG_ARTIST)) != NULL) {
904                 list = g_list_append(list, g_strdup(pair->value));
905                 mpd_return_pair(c->connection, pair);
906         }
908         if (mpdclient_finish_command(c))
909                 return string_list_free(list);
911         return list;
914 GList *
915 mpdclient_get_albums(struct mpdclient *c, const gchar *artist_utf8)
917         GList *list = NULL;
918         struct mpd_pair *pair;
920         if (MPD_ERROR(c))
921                return NULL;
923         mpd_search_db_tags(c->connection, MPD_TAG_ALBUM);
924         if (artist_utf8 != NULL)
925                 mpd_search_add_tag_constraint(c->connection,
926                                               MPD_OPERATOR_DEFAULT,
927                                               MPD_TAG_ARTIST, artist_utf8);
928         mpd_search_commit(c->connection);
930         while ((pair = mpd_recv_pair_tag(c->connection,
931                                          MPD_TAG_ALBUM)) != NULL) {
932                 list = g_list_append(list, g_strdup(pair->value));
933                 mpd_return_pair(c->connection, pair);
934         }
936         if (mpdclient_finish_command(c))
937                 return string_list_free(list);
939         return list;